Si alguna vez planee buscar atributos específicos, es una mala idea serializarlos en una sola columna, ya que tendrá que usar funciones por fila para obtener la información; esto rara vez se escala bien.
Yo optaría por tu segunda opción. Tenga una lista de atributos en una tabla de atributos, los objetos en su propia tabla y una tabla de relaciones de muchos a muchos llamada atributos de objetos.
Por ejemplo:
objects:
object_id integer
object_name varchar(20)
primary key (object_id)
attributes:
attr_id integer
attr_name varchar(20)
primary key (attr_id)
object_attributes:
object_id integer references (objects.object_id)
attr_id integer references (attributes.attr_id)
oa_value varchar(20)
primary key (object_id,attr_id)
Se nota su preocupación por el rendimiento pero, según mi experiencia, siempre es más costoso dividir una columna que combinar varias columnas. Si resulta que hay problemas de rendimiento, es perfectamente aceptable romper 3NF por motivos de rendimiento.
En ese caso, lo almacenaría de la misma manera pero también tendría una columna con los datos serializados sin procesar. Siempre que utilice disparadores de inserción/actualización para mantener sincronizados los datos en columnas y combinados, no tendrá ningún problema. Pero no debe preocuparse por eso hasta que surja un problema real.
Al usar esos disparadores, minimiza el trabajo requerido para solo cuando los datos cambian. Al tratar de extraer información de subcolumnas, hace un trabajo innecesario en cada seleccionar.