Tipo de datos para almacenar una matriz de banderas (un mapa de bits / matriz de bits)

15

Necesito almacenar una matriz de bits para cada registro de una tabla, admitiendo las siguientes operaciones:

  • Probar si se establece un bit y establecer un bit (usando SQL)

  • Consultar y establecer el valor usando ADO 2.8 (no ADO.NET)

  • Indexación (para beneficiarse de la función "índice de cobertura")

El número máximo de bits que se almacenarán en esta matriz es fijo, pero puede superar los 32 . Es decir, una columna int simple no siempre funciona.

Por lo que he visto hasta ahora, mis opciones son:

  1. Use varias columnas int
  2. Use bigint (funciona siempre que el número de bits sea <= 64)
  3. Usar binario
  4. ?

La primera opción funcionaría, pero requiere un poco de refactorización en el código que accede a los datos. La segunda opción es solo un alivio temporal, y de mis búsquedas hasta ahora no estoy muy seguro de si ADO funciona tan bien con bigint . No tengo experiencia con binarios , y no conozco ninguna otra opción.

¿Qué tipo de datos elegiría, dados los requisitos?

krlmlr
fuente

Respuestas:

12

No puedo defender lo suficiente como para no usar un solo campo para esto.

Actualmente estoy tratando de mantener un conjunto de datos muy grande con un bigintcampo de máscara de bits y es una pesadilla de rendimiento.

Si marca un solo bit está bien. Si verifica más de un bit, el rendimiento se degrada muy rápidamente.

Debido a la naturaleza de los enteros de máscara de bits, la distribución de datos estará muy desequilibrada y obtendrá planes subóptimos.

Las comprobaciones de bits múltiples dan como resultado escaneos de rango o índice con una función que se ejecuta en cada fila. Es un desastre.

Mi solución era simple: hice una tabla para almacenar el PK para cada una de las condiciones que se comprobarán. Inicialmente, esto es contra-intuitivo, pero el espacio necesario es bajo (solo almacena el PK) y las búsquedas son muy rápidas, especialmente si usa a UNIQUE CLUSTERED INDEX.

Puede agregar tantas condiciones como desee sin afectar su tabla principal, y las actualizaciones tampoco afectan su tabla principal.

La indexación es simple ya que solo indexa todas las tablas de búsqueda individualmente, y dado que su clave agrupada es la misma en su tabla principal y las búsquedas, todas sus evaluaciones merge joinson muy eficientes.

JNK
fuente
1
¿Podría elaborar un poco más sobre su solución? Encontré esto porque estoy tratando de abordar el mismo problema básico, pero no estoy seguro de cuál es la mejor manera de hacerlo.
Joshua Frank el
4

Si todo lo que necesita almacenar es un número moderado de valores verdadero / falso, puede usar el bittipo de datos.

Internamente, SQL Server almacena bitcolumnas empaquetadas en "fragmentos" de bytes. Entonces, para hasta 8 bitcolumnas en su tabla, SQL almacena eso como un 1 byte empaquetado; 9-16 bitcolumnas en 2 bytes, y así sucesivamente.

No parece que vaya a acercarse al límite de la columna, por lo que parece bastante sencillo. Y, por supuesto, mantenerlos bien separados de esa manera le permite nombrar las columnas para facilitar la lectura y obtener todas las posibilidades de indexación que normalmente tendría (si los indicadores son altamente selectivos, los índices filtrados pueden ser útiles si puede apuntar a 2008+).

Hacer el empaquetado de bits usted mismo hará que sea mucho más complicado hacer indexación (probablemente bitcolumnas calculadas e indexadas para representar cada posición de la máscara ... pero entonces está peor en comparación con el uso bitdirecto).

Jon Seigel
fuente