¿Es realmente tan malo almacenar una lista delimitada en una columna de base de datos?

Imagine un formulario web con un conjunto de casillas de verificación (se pueden seleccionar cualquiera o todos ellos). Elegí guardarlos en una lista de valores separados por comas almacenados en una columna de la tabla de la base de datos.

Ahora, sé que la solución correcta sería crear una segunda tabla y normalizar correctamente la base de datos. Fue más rápido implementar la solución fácil, y quería tener una prueba de concepto de esa aplicación rápidamente y sin tener que dedicarle demasiado tiempo.

Pensé que el tiempo ahorrado y el código más simple valían la pena en mi situación, ¿es esta una opción de diseño defendible, o debería haberla normalizado desde el principio?

Un poco más de contexto, esta es una pequeña aplicación interna que esencialmente reemplaza un archivo de Excel que se almacenó en una carpeta compartida. También estoy preguntando porque estoy pensando en limpiar el progtwig y hacerlo más fácil de mantener. Hay algunas cosas que no me satisfacen del todo, una de ellas es el tema de esta pregunta.

Además de violar la Primera Forma Normal debido al grupo repetitivo de valores almacenados en una sola columna, las listas separadas por comas tienen muchos otros problemas más prácticos:

  • No se puede asegurar que cada valor sea del tipo de datos correcto: no hay forma de prevenir 1,2,3, banana, 5
  • No se pueden usar restricciones de clave externa para vincular valores a una tabla de búsqueda; no hay forma de hacer cumplir la integridad referencial.
  • No se puede forzar la exclusividad: no hay manera de prevenir 1,2,3,3,3,5
  • No se puede eliminar un valor de la lista sin recuperar toda la lista.
  • No se puede almacenar una lista más larga que la que cabe en la columna de cadena.
  • Difícil buscar todas las entidades con un valor dado en la lista; tienes que usar un escaneo de tabla ineficiente. Puede tener que recurrir a expresiones regulares, por ejemplo en MySQL:
    idlist REGEXP '[[:<:]]2[[:>:]]' *
  • Es difícil contar elementos en la lista, o hacer otras consultas agregadas.
  • Es difícil unir los valores a la tabla de búsqueda a la que hacen referencia.
  • Es difícil buscar la lista en orden ordenado.
  • Almacenar enteros como cadenas requiere aproximadamente el doble de espacio que almacenar enteros binarios. Sin mencionar el espacio tomado por los personajes de coma.

Para resolver estos problemas, debe escribir toneladas de código de la aplicación, reinventando la funcionalidad que el RDBMS ya proporciona de manera mucho más eficiente .

Las listas separadas por comas son lo suficientemente incorrectas como para convertirlo en el primer capítulo de mi libro: Antipatterns de SQL: evitar las trampas de la progtwigción de bases de datos .

Hay momentos en los que necesita emplear desnormalización, pero como @OMG Ponies menciona , estos son casos excepcionales. Cualquier “optimización” no relacional beneficia a un tipo de consulta a expensas de otros usos de los datos, así que asegúrese de saber cuáles de sus consultas necesitan tratamiento, especialmente si merecen una desnormalización.


* MySQL 8.0 ya no admite esta syntax de expresión de límite de palabras.

Hay numerosas preguntas sobre SO preguntando:

  • cómo obtener un recuento de valores específicos de la lista separada por comas
  • cómo obtener registros que tengan solo el mismo valor específico de 2/3 / etc de esa lista separada por comas

Otro problema con la lista separada por comas es garantizar que los valores sean coherentes: almacenar texto significa la posibilidad de errores tipográficos …

Todos estos son síntomas de datos desnormalizados, y destacan por qué siempre debe modelar para datos normalizados. La desnormalización puede ser una optimización de la consulta, que se aplicará cuando realmente se presente la necesidad .

“Una de las razones fue la pereza”.

Esto hace sonar las alarmas. La única razón por la que debes hacer algo así es que sabes cómo hacerlo “de la manera correcta”, pero has llegado a la conclusión de que hay una razón tangible para no hacerlo de esa manera.

Habiendo dicho esto: si los datos que elige almacenar de esta manera son datos que nunca necesitará consultar, puede haber un caso para almacenarlos de la manera que ha elegido.

(Algunos usuarios disputarían la afirmación en mi párrafo anterior, diciendo que “nunca se sabe qué requisitos se agregarán en el futuro”. Estos usuarios están equivocados o declaran una convicción religiosa. A veces es ventajoso trabajar según los requisitos que ten delante de ti.)

En general, cualquier cosa puede ser defendible si cumple con los requisitos de su proyecto. Esto no significa que las personas estén de acuerdo o quieran defender su decisión …

En general, el almacenamiento de datos de esta manera no es óptimo (por ejemplo, es más difícil realizar consultas eficientes) y puede causar problemas de mantenimiento si modifica los elementos en su formulario. ¿Quizás podría haber encontrado un término medio y usar un número entero que representa un conjunto de banderas de bits en su lugar?

Sí, yo diría que realmente es tan malo. Es una elección defendible, pero eso no lo hace correcto o bueno.

Se rompe la primera forma normal.

Una segunda crítica es que al poner los resultados de entrada sin procesar directamente en una base de datos, sin ninguna validación o vinculación, lo deja abierto a los ataques de inyección de SQL.

Lo que llamas holgazanería y falta de conocimiento de SQL es lo que hacen los neófitos. Recomiendo tomarse el tiempo para hacerlo correctamente y verlo como una oportunidad para aprender.

O déjalo como está y aprende la dolorosa lección de un ataque de inyección SQL.

Necesitaba una columna con varios valores, podría implementarse como un campo xml

Se podría convertir a una coma delimitada según sea necesario

consultar una lista XML en el servidor sql usando Xquery .

Al ser un campo xml, se pueden abordar algunas de las inquietudes.

Con CSV: no se puede asegurar que cada valor sea el tipo de datos correcto: no hay manera de evitar 1,2,3, banana, 5

Con XML: los valores en una etiqueta pueden ser forzados a ser del tipo correcto


Con CSV: no se pueden usar restricciones de clave externa para vincular valores a una tabla de búsqueda; no hay forma de hacer cumplir la integridad referencial.

Con XML: sigue siendo un problema


Con CSV: no se puede forzar la exclusividad: no hay forma de prevenir 1,2,3,3,3,5

Con XML: sigue siendo un problema


Con CSV: no se puede eliminar un valor de la lista sin recuperar toda la lista.

Con XML: se pueden eliminar elementos individuales


Con CSV: es difícil buscar todas las entidades con un valor dado en la lista; tienes que usar un escaneo de tabla ineficiente.

Con XML: el campo xml puede ser indexado


Con CSV: es difícil contar elementos en la lista, o hacer otras consultas agregadas. **

Con XML: no particularmente difícil


Con CSV: es difícil unir los valores a la tabla de búsqueda a la que hacen referencia. **

Con XML: no particularmente difícil


Con CSV: difícil de obtener la lista en orden ordenado.

Con XML: no particularmente difícil


Con CSV: almacenar enteros como cadenas requiere aproximadamente el doble de espacio que almacenar enteros binarios.

Con XML: el almacenamiento es incluso peor que un csv


Con CSV: además de muchos personajes de coma.

Con XML: se usan tags en lugar de comas


En resumen, el uso de XML soluciona algunos de los problemas con la lista delimitada Y se puede convertir a una lista delimitada según sea necesario

Sí, es así de malo. Mi opinión es que si no le gusta usar bases de datos relacionales y luego busca una alternativa que le convenga mejor, hay muchos proyectos “NOSQL” interesantes con algunas características realmente avanzadas.

Bueno, he estado usando una lista separada por pares de clave / valor en una columna NTEXT en SQL Server por más de 4 años y funciona. Usted pierde la flexibilidad de realizar consultas, pero, por otro lado, si tiene una biblioteca que persista / desvirtúa el par de valores clave, entonces no es una mala idea.

Probablemente tomaría el término medio: convierta cada campo en el archivo CSV en una columna separada en la base de datos, pero no se preocupe demasiado por la normalización (al menos por ahora). En algún momento, la normalización puede volverse interesante, pero con todos los datos incorporados en una única columna, prácticamente no obtiene ningún beneficio del uso de una base de datos. Debe separar los datos en campos lógicos / columnas / como quiera que los llame antes de poder manipularlos significativamente.