2008-10-23 10 views
82

Recuerdo haber leído en un momento dado que indexar un campo con baja cardinalidad (un número bajo de valores distintos) no vale realmente la pena. Admito que no sé lo suficiente sobre cómo funcionan los índices para entender por qué es así.¿Debo indexar un campo de bit en SQL Server?

¿Qué sucede si tengo una tabla con 100 millones de filas y estoy seleccionando registros donde un campo de bit es 1? Y digamos que en cualquier punto del tiempo, solo hay un puñado de registros donde el campo de bit es 1 (en oposición a 0). ¿Vale la pena indexar ese campo de bit o no? ¿Por qué?

Por supuesto que solo puedo probarlo y verificar el plan de ejecución, y lo haré, pero también tengo curiosidad acerca de la teoría detrás de esto. ¿Cuándo importa la cardinalidad y cuándo no?

+0

En caso de que no lo haya leído, Jason Massie recientemente escribió un artículo que discutió este tema. http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx Editar: Ubicación de artículo nuevo - http://sqlserverpedia.com/blog/sql-server -bloggers/never-index-a-bit – Jeff

+0

Por sí solo, no, ya que resulta en muy poca selectividad. Como parte de un índice compuesto. muy posiblemente, pero solo después de otras columnas de igualdad. –

+0

¿Es esta una consulta común? Puede valer la pena al buscar el "puñado" de registros pero no le ayudará mucho en las otras filas.¿Hay otras formas de identificar los datos? –

Respuesta

61

Considere lo que es un índice en SQL, y el índice es realmente un trozo de memoria que señala otros trozos de memoria (es decir, punteros a filas). El índice está dividido en páginas para que partes del índice puedan cargarse y descargarse de la memoria dependiendo del uso.

Cuando solicita un conjunto de filas, SQL usa el índice para buscar las filas más rápidamente que el escaneo de tablas (examinando cada fila).

SQL tiene índices agrupados y no agrupados. Mi comprensión de los índices agrupados es que agrupan valores de índice similares en la misma página. De esta forma, cuando solicite todas las filas que coincidan con un valor de índice, SQL puede devolver esas filas desde una página de memoria agrupada. Esta es la razón por la que tratar de agrupar el índice de una columna GUID es una mala idea: no intente agrupar los valores aleatorios.

Al indexar una columna entera, el índice de SQL contiene un conjunto de filas para cada valor de índice. Si tiene un rango de 1 a 10, entonces tendría 10 punteros de índice. Dependiendo de cuántas filas hay, esto se puede paginar de manera diferente. Si su consulta busca el índice "1" y luego el nombre contiene "Fred" (asumiendo que la columna Nombre no está indexada), SQL obtiene el conjunto de filas que coinciden con "1" muy rápidamente, luego escanea la tabla para encontrar el resto.

Entonces, lo que SQL realmente está haciendo es intentar reducir el conjunto de trabajo (número de filas) sobre el que debe iterar.

Cuando indexa un campo de bit (o un rango estrecho), solo reduce el conjunto de trabajo por el número de filas que coinciden con ese valor. Si tiene un número pequeño de filas que coincidan, reduciría mucho su conjunto de trabajo. Para una gran cantidad de filas con una distribución de 50/50, es posible que le compre muy poco rendimiento y mantenga el índice actualizado. El motivo por el que todo el mundo dice probar es porque SQL contiene un optimizador muy inteligente y complejo que puede ignorar un índice si decide que el escaneo de tabla es más rápido, o puede ordenar, o puede organizar páginas de memoria como prefiera.

+0

Parece que si tengo un puñado de filas donde el campo de bit es 1 (por ejemplo, el seguimiento de "IsProcessed"), entonces un índice sería bueno porque las ordenará por valor y luego podrá seleccionar el pequeño trabajo conjunto muy rápido. Si está de acuerdo, agréguelo y lo aceptaré. – jeremcc

+2

Lo que quiero decir en mi comentario anterior es que esta afirmación: "Cuando indexa un campo de bit (o un rango estrecho), solo reduce el conjunto de trabajo a la mitad" no es verdadero si la distribución está muy ponderada un valor Pero me gusta el resto de tu respuesta, así que si corriges eso, lo aceptaré. – jeremcc

+1

Hecho. Estaba pensando que para un millón de filas, un campo de bits tendría una distribución del 50%, pero tiene razón en que para un espacio problemático en particular podría reducir mucho el conjunto de trabajo. –

0

medida tiempo de respuesta antes y después y ver si vale la pena; teóricamente debería mejorar el rendimiento de las consultas utilizando los campos indexados, pero realmente depende de la distribución de los valores verdaderos/falsos y de los otros campos involucrados en las consultas que le preocupan

0

¿Es esta una consulta común? Puede valer la pena al buscar el "puñado" de registros pero no le ayudará mucho en las otras filas. ¿Hay otras formas de identificar los datos?

1

Si desea saber si un índice tiene los efectos que desea: pruebe y vuelva a probar.

En general, no desea un índice que no limite suficientemente su tabla, debido al costo de mantener un índice. (costo> ganancia). Pero si el índice en su caso reducirá la tabla a la mitad, puede ganar algo pero ponerlo sobre la mesa. Todo depende del tamaño/estructura exacta de su tabla y de cómo la está usando (número de lecturas/escrituras).

2

Por supuesto que vale la pena, especialmente si necesita recuperar los datos por ese valor. Sería similar a usar una matriz dispersa en lugar de usar una matriz normal.

Ahora con SQL 2008 puede usar funciones de particionamiento, y puede filtrar los datos que van en un índice. La desventaja de versiones anteriores sería que el índice se haría para todos los datos, pero esto se puede optimizar almacenando los valores interesantes en un grupo de archivos separado.

2

Como han dicho otros, querrá medir esto. No recuerdo dónde he leído esto, pero una columna necesita tener una cardinalidad muy alta (alrededor del 95%) para que un índice sea efectivo. Su mejor prueba para esto sería construir el índice y examinar los planes de ejecución para los valores 0 y 1 del campo BIT. Si ve una operación de búsqueda de índice en el plan de ejecución, sabrá que se usará su índice.

Lo mejor que puede hacer es probar con un SELECCIONAR * BASE * FROM tabla DONDE BitField = 1; consulta y desarrolla lentamente la funcionalidad a partir de ahí paso a paso hasta que tengas una consulta realista para tu aplicación, examinando el plan de ejecución con cada paso para asegurarte de que la búsqueda del índice aún se esté utilizando. Es cierto que no hay garantía de que este plan de ejecución se utilizará en producción, pero hay muchas posibilidades de que así sea.

Parte de la información se puede encontrar en la sql-server-performance.com forums y en el que se hace referencia article

+0

No importa tanto la cardinalidad de la columna como un todo. Es la selectividad de la cláusula WHERE. Entonces, si hay pocas columnas con valor 1, todavía puede ser bueno indexar. Si es 50/50 (por ejemplo, hombre/mujer), entonces no vale la pena. –

6

Aunque no creo que lo haría sólo un índice de columna de bits por sí mismo, es muy común incluir columnas de bits como parte de un compuesto índice.

Un ejemplo simple sería un índice en ACTIVE, LASTNAME en lugar de solo lastname, cuando su aplicación casi siempre busca clientes activos.

+5

En el ejemplo que dio, me inclinaría más a poner Apellido primero. Depende de la carga de trabajo de consulta específica, pero en general tener primero la columna más selectiva significa que es más probable que se use el índice. –

2

"Recuerdo haber leído en un momento que la indexación de un campo con baja cardinalidad (un bajo número de valores distintos) no es realmente vale la pena hacerlo"

Eso porque SQL Server casi siempre encontrará su más eficiente simplemente hacer un escaneo de tabla que leer el índice. Así que, básicamente, su índice nunca se utilizará y es un desperdicio mantenerlo. Como otros han dicho, podría estar bien en un índice compuesto.

0

La cardinalidad es un factor, el otro es qué tan bien divide el índice sus datos. Si tiene aproximadamente la mitad 1s y la mitad 0s, entonces ayudará. (Suponiendo que ese índice es una mejor ruta para elegir que algún otro índice). Sin embargo, ¿con qué frecuencia está insertando y actualizando? La adición de índices para el rendimiento SELECT también perjudica a INSERTAR, ACTUALIZAR y ELIMINAR el rendimiento, así que tenlo en cuenta.

Yo diría, si el 1s a 0s (o viceversa) no es mejor que el 75% al ​​25%, no se moleste.

+0

No estoy de acuerdo. Si su distribución es 50/50, nunca usaría el índice, ya que sería más rápido hacer un escaneo de tabla. Sin embargo, si solo tiene 5, 1 valores y 1 millón 0 de valores, es muy probable que use el índice cuando busque 1. – Kibbee

1

Usted no puede índice de un campo de bits de SQL Server 2000, como se indica en los libros en pantalla en el momento:

poco

entero de datos de tipo 1, 0, o NULO.

Observaciones

columnas de tipo poco no puede tener índices sobre ellos.

Sí, si solo tiene un puñado de filas, de millones, un índice lo ayudará. Pero si desea hacerlo en este caso, debe hacer que la columna sea tinyint.

Nota: Enterprise Manager no le permitirá crear un índice en una columna de bits. Si lo desea, todavía puede crear manualmente un índice en una columna de bits:

CREATE INDEX IX_Users_IsActiveUsername ON Users 
(
    IsActive, 
    Username 
) 

Pero SQL Server 2000 en realidad no utilizar un índice de este tipo - ejecutar una consulta en el que el índice sería un candidato perfecto, por ejemplo:

SELECT TOP 1 Username 
FROM Users 
WHERE IsActive = 0 

SQL Server 2000 hará una exploración de tabla, actuando como si el índice no existiera. Si cambia la columna a tinyint SQL Server 2000 , realizará una búsqueda de índice. Además, la siguiente consulta que no está cubierto:

SELECT TOP 1 * 
FROM Users 
WHERE IsActive = 0 

Se llevará a cabo una búsqueda de índice, seguida de una búsqueda de marcador.


SQL Server 2005 tiene un soporte limitado para índices en columnas de bits.Por ejemplo:

SELECT TOP 1 Username 
FROM Users 
WHERE IsActive = 0 

provocará una búsqueda de índice a través del índice de cobertura. Pero el caso no cubierto:

SELECT TOP 1 * 
FROM Users 
WHERE IsActive = 0 

no causará una búsqueda de índice seguida de una búsqueda de marcador, se llevará a cabo un recorrido de tabla (o recorrido de índice agrupado), en lugar de realizar la búsqueda de índice seguida de una búsqueda de marcador .

Verificado por experimentación y observación directa.

+0

FYI - SQL Server 2005 Management Studio le permite hacerlo. – jeremcc

+0

Mi copia de SQL Server 2000 me permitió establecer un índice en una columna de bits. – Kibbee

+0

Mi copia de SQL Server 2000 no me permite establecer un índice en una columna de bits. –

1

Por sí solo, no ya que resulta en muy poca selectividad. Como parte de un índice compuesto. muy posiblemente, pero solo después de otras columnas de igualdad.

9

100 millones de registros con solo unos pocos con el campo de bit establecido en 1? Sí, creo que indexar el campo de bit definitivamente aceleraría la consulta de los bits = 1 registros. Debería obtener el tiempo de búsqueda logarítmica del índice y luego solo tocar las pocas páginas con bit = 1 registros. De lo contrario, tendría que tocar todas las páginas de la tabla de registro de 100 millones.

Por otra parte, definitivamente no soy un experto en bases de datos y podría perder algo importante.

2

Si su objetivo es hacer consultas para registros donde el valor del campo de bit es igual a '1' más rápido, puede probar una vista indexada de su tabla base que solo contiene registros donde su campo de bit es igual a '1'.En la edición empresarial, si una consulta puede hacer uso de una vista indexada en lugar de una tabla específica para mejorar el rendimiento de la consulta, usará la vista. En teoría, esto aumentaría la velocidad de las consultas de selección que solo buscan registros con un valor de campo de bit de '1'.

http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx

Todo esto supone son Microsoft SQL Server 2005 Enterprise. Lo mismo podría aplicarse a 2008, no estoy familiarizado con esa versión.

+0

Sería bueno si alguien probara esto ... –

6

En caso de que no lo haya leído, Jason Massie recientemente escribió un artículo que discutió este tema.

http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx

edición: Nueva artículo de la localización - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit

máquina de Wayback para anterioridad "nuevo" artículo de la localización: http://web.archive.org/web/20120201122503/http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/

La nueva ubicación de SQL Server Pedia es Toadworld, que tiene un nuevo artículo de Kenneth Fisher al discutir este tema:

http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be-used.aspx

+0

este artículo ya no está visible – Homer6

+0

@ Homer6 Agregué un enlace a lo que parece el nuevo hogar para este artículo. – Jeff

+0

excelente ... thx :-) – Homer6

0

Ian Boyd tiene razón cuando dice que no puede hacerlo a través de Enterprise Manager para SQL 2000 (consulte su nota sobre cómo crearlo a través de T-SQL.

1

respuesta muy tarde ...

Sí, puede ser useful according to SQL CAT team (actualizado, se ha consolidado)

+1

El enlace parece estar muerto ahora. Sin embargo, esa publicación parece haberse consolidado junto con varias otras en un [e-book] (http://download.microsoft.com/download/0/F/B/0FBFAA46-2BFD-478F-8E56-7BF3C672DF9D/SQLCAT's % 20Guide% 20to% 20Relational% 20Engine.pdf). La sección a la que se hace referencia comienza en la página 86. El libro electrónico se puede descargar desde [libros electrónicos de SQLCAT.com] (http://blogs.msdn.com/b/sqlcat/archive/2013/10/23/sqlcat-com-ebook -downloads.aspx) bajo el enlace "Guía de SQLCAT para motor relacional". – mwolfe02

13

me encontré con esta pregunta por medio de otro. Suponiendo que su afirmación de que solo un puñado de registros asume el valor de 1 (y que esos son los que le interesan), entonces un índice filtrado podría ser una buena opción. Algo así como:

create index [IX_foobar] on dbo.Foobar (FooID) where yourBitColumn = 1 

Esto creará un índice sustancialmente menor que el optimizador es lo suficientemente inteligente como para usar cuando es un predicado de la consulta.

+0

Vale la pena señalar que el predicado en la consulta debe codificarse con el valor en el índice filtrado. Si pasa el valor en un parámetro 'yourBitColumn = @ value', entonces el optimizador no puede determinar si el índice filtrado es utilizable. – geofftnz

+1

Hay formas de evitar esto, pero tienes razón; el optimizador necesita una garantía en tiempo de compilación de que los valores para cualquier predicado que coincida con el predicado de índice filtrado sean estáticos/invariables, ya que es tarea del optimizador crear un plan general que funcione para * cualquier * conjunto de parámetros. –

2

Si su distribución es bastante conocida y desequilibrada, como el 99% de las filas son bit = 1 y el 1% son bit = 0, cuando hace una cláusula WHERE con bit = 1, habrá una exploración de tabla completa al mismo tiempo que el escaneo de índice. Si desea tener una consulta rápida donde bit = 0, la mejor manera que conozco es crear un índice filtrado, agregando una cláusula WHERE bit = 0. De esta manera, ese índice solo almacenará la fila del 1%. Luego, haciendo un WHERE bit = 0 simplemente dejará que el optimizador de consultas elija ese índice, y todas las filas serán bit = 0. También tiene la ventaja de tener una cantidad muy pequeña de espacio en disco requerido comparar un índice completo en el bit .

0

Debe ser inteligente aquí para realizar consultas, debe saber el valor de la carga en su columna si la carga de la verdad está más en su sistema y desea verificar todos los valores verdaderos para verificar la consulta. ayudará mucho, solo engaña.

Cuestiones relacionadas