2010-12-26 12 views
6

He visto algunos enfoques posibles (en algunos motores de base de algunos de ellos son sinónimos):¿Cuál es la forma óptima de almacenar indicadores binarios/valores booleanos en cada motor de base de datos?

  1. TINYINT (1)
  2. BOOL
  3. BIT (1)
  4. ENUM (0,1)
  5. CHAR (0) NULL

Todo motor de base de datos importante el apoyo de PHP debe tenerse en cuenta, pero sólo como un refference que va a ser aún mejor si también o Se notarán los motores.

Estoy pidiendo un diseño que sea mejor optimizado para leer. p. SELECCIONANDO con el campo de bandera en la condición WHERE, o GROUP BY el indicador. El rendimiento es mucho más importante que el espacio de almacenamiento (excepto cuando el tamaño tiene un impacto en el rendimiento).

y algunos detalles más:

bien la creación de la tabla no puedo saber si será escasa (si la mayoría de las banderas están encendidos o apagados), pero puede alterar las tablas más adelante, así que si hay es algo que puedo optimizar si lo sé, debe tenerse en cuenta.

Además, si hace una diferencia si solo hay un indicador (o unos pocos) por fila, en comparación con muchos (o muchos) indicadores, debe tenerse en cuenta.

Por cierto, he leído en algún lugar de por lo que el siguiente:

Usando booleano puede hacer lo mismo que usando tinyint, sin embargo, tiene la ventaja de semánticamente transportar lo que su intención es, y eso es vale la pena algo.

Bueno, en mi caso no vale nada, porque cada tabla está representada por una clase en mi aplicación y todo está explícitamente definido en la clase y bien documentado.

Respuesta

6

Esta respuesta es para el estándar SQL ISO/IEC/ANSI, e incluye el mejor freeware pretend-SQL.

El primer problema es que ha identificado dos categorías, ninguna, por lo que no se pueden comparar razonablemente.

A. Categoría Uno

(1) (4) y (5) contienen varios valores posibles y son de una categoría. Todo se puede usar fácil y efectivamente en la cláusula WHERE. Tienen el mismo almacenamiento, por lo que ni el almacenamiento ni el rendimiento de lectura son un problema. Por lo tanto, la elección restante se basa simplemente en el tipo de datos real para el propósito de la columna.

ENUM no es estándar; el método mejor o estándar es usar una tabla de búsqueda; entonces los valores son visibles en una tabla, no ocultos, y pueden ser enumerados por cualquier herramienta de informe. El rendimiento de lectura de ENUM sufrirá un pequeño golpe debido al procesamiento interno.

B. Categoría Dos

(2) y (3) son dos valores-elementos: Verdadero/Falso; Macho femenino; Muerto vivo. Esa categoría es diferente a la Categoría Uno. Su tratamiento tanto en su modelo de datos como en cada plataforma es diferente. BOOLEAN es solo un sinónimo de BIT, son lo mismo. Legalmente (SQL-wise), todas las plataformas compatibles con SQL manejan de la misma manera, y no hay ningún problema al utilizarla en la cláusula WHERE.

La diferencia de rendimiento depende de la plataforma. Sybase y DB2 empaquetan hasta 8 BIT en un byte (no es que el almacenamiento sea importante aquí), y asignan el poder de los dos sobre la marcha, por lo que el rendimiento es realmente bueno.Oracle hace cosas diferentes en cada versión, y he visto que los modeladores usan CHAR (1) en lugar de BIT, para superar los problemas de rendimiento. MS estuvo bien hasta 2005, pero lo han roto con 2008, ya que los resultados son impredecibles; entonces la respuesta corta puede ser implementarlo como CHAR (1).

Por supuesto, la suposición es que no hace cosas tontas, como empacar 8 columnas separadas en un TININT. No solo es un grave error de normalización, es una pesadilla para los codificadores. Mantenga cada columna discreta y del tipo de datos correcto.

C. Indicadores Múltiples & columnas anulables

Esto no tiene nada que ver con, y es independiente de, (A) y (B). Lo que las columnas corrigen es el tipo de datos, es diferente a la cantidad que tiene y si es Nullable. Nullable significa (generalmente) la columna es opcional. Esencialmente no has completado el ejercicio de modelado o normalización. Las Dependencias Funcionales son ambiguas. si completa el ejercicio de Normalización, no habrá columnas Nullable, no columnas opcionales; o bien existen claramente para una relación particular, o no existen. Eso significa usar la estructura relacional ordinaria de Supertype-Subtypes.

Claro, eso significa más tablas, pero no nulos. Enterpise DBMS no tiene problemas con más tablas o más uniones, para eso están optimizadas. Las bases de datos normalizadas funcionan mucho mejor que las no desnaturalizadas o denormalizadas, y pueden ampliarse sin "refactorizar". Puede facilitar el uso suministrando una vista para cada subtipo.

Si desea obtener más información sobre este tema, mire en este question/answer. Si necesita ayuda con el modelado, por favor, hacer una nueva pregunta. en el nivel de cuestionamiento, yo le aconsejaría que se quede con 5NF.

D. rendimiento de valores nulos

por otra parte, si el rendimiento es importante para usted, luego excluya los valores nulos. Cada columna anulable se almacena como longitud variable, lo que requiere un procesamiento adicional para cada fila/columna. s use un manejo "diferido" para tales filas, para permitir el registro, etc. para mover las colas de pensamiento sin obstaculizar las filas fijas. En particular, nunca utilice columnas de longitud variable (que incluye columnas con anulabilidad) en un índice: eso requiere desempaquetar en cada acceso.

E. Encuesta

Por último, no veo el punto en esta pregunta es una encuesta. Es justo que obtenga respuestas técnicas e incluso opiniones, pero las encuestas son para concursos de popularidad, y la capacidad técnica de los que responden en SO cubre un rango muy amplio, por lo que las respuestas más populares y las más técnicamente correctas están en dos diferentes extremos del espectro.

+0

Podría incluir un enlace o más información sobre cómo "MS estuvo bien hasta 2005 pero lo han roto con 2008, ya que los resultados son impredecibles" y si está roto en 2K8R2 –

+2

@RC. No tengo enlaces, tengo experiencia. Wiki aún no ha escuchado sobre esto. Los resultados del contexto específico anterior, y algunos otros, no todos los contextos, son impredecibles; si tuviste un código que tuvo un buen desempeño en 2005. He publicado muchos otros datos específicos: eliminación de páginas de desbordamiento y daño a todo el rendimiento en índices agrupados, etc. No dudes en leerlos. No se corrigió en Rev 2. No hay posibilidad de que estos elementos se arreglen hasta Rev 4 al menos. Tomó MS más de 3 años para arreglar 2005. – PerformanceDBA

1

Sé que esta no es la respuesta que desea, pero la diferencia es realmente despreciable en todos, excepto en los casos especiales más extremos. Y en cada caso específico, simplemente cambiar el tipo de datos no será suficiente para solucionar un problema de rendimiento.

Por ejemplo, aquí hay algunas alternativas que superarán por mucho a cualquier cambio de tipo de datos. Cada uno lleva consigo un inconveniente, por supuesto.

Si tiene 200 indicadores opcionales y consulta como máximo de 1 a 2 a la vez para muchas filas, obtendrá un mejor rendimiento al tener cada indicador en su propia tabla. Si los datos son realmente escasos, esto mejora aún más.

Si tiene 200 marcas obligatorias y solo realiza búsquedas de registros individuales, debe ponerlos en la misma tabla.

Si tiene un pequeño conjunto de indicadores, puede empaquetarlos en una columna usando una máscara de bits, que es eficiente en cuanto al almacenamiento, pero no podrá (fácilmente) consultar indicadores individuales. Por supuesto, esto no funciona cuando las banderas pueden ser NULL ...

O puede ser creativo y utilizar un concepto de "dimensión basura", en el que crea una tabla separada con los 200 indicadores booleanos representados como columnas. Crea una fila para cada combinación distinta de valores de bandera. Cada fila obtiene una clave primaria autoincrement, a la que hace referencia en el registro maestro. Voila, la tabla maestra ahora contiene 1 int, en lugar de 200 columnas . El cielo de los hackers, la pesadilla del DBA.

Lo que quiero decir es que, aunque es interesante discutir cuál es "el mejor", hay otras preocupaciones que son de mucha mayor importancia (como el comentario que citó). Simplemente porque cuando encuentre un problema de rendimiento real, el tipo de datos no será el problema ni la solución.

0

Cualquiera de los anteriores está bien y tengo una preferencia personal de usar BOOL si está bien soportado porque eso mejor transmite tu intención pero evitaría usar ENUM(0,1). El primer problema con ENUM es que requiere que su valor sea una cadena. 0 y 1 parece un número, por lo que los programadores tienden a enviar un número.

El segundo problema con ENUM es que si le envía un valor incorrecto se convierte por defecto en la primera enumeración y en algunas bases de datos ni siquiera indicará un error (estoy viendo MySQL). Esto empeora el primer problema ya que si accidentalmente lo envía 1 en lugar de "1", almacenará el valor "0" - ¡muy contrario a la intuición!

No creo que esto afecte a todos los motores de base de datos (no sé, no los he probado todos) pero afecta a muchos de ellos como para evitar que sea una buena práctica.

Cuestiones relacionadas