Recuerdo haber leído en un momento que no vale la pena indexar un campo con cardinalidad baja (un número bajo de valores distintos). Admito que no sé lo suficiente sobre cómo funcionan los índices para entender por qué es así.
Entonces, ¿qué pasa si tengo una tabla con 100 millones de filas y estoy seleccionando registros donde un campo de bits es 1? Y digamos que en cualquier momento, solo hay un puñado de registros donde el campo de bits es 1 (en lugar de 0). ¿Vale la pena indexar ese campo de bits o no? ¿Por qué?
Por supuesto, puedo probarlo y verificar el plan de ejecución, y lo haré, pero también tengo curiosidad por la teoría detrás de esto. ¿Cuándo importa la cardinalidad y cuándo no?
sql-server
indexing
jeremcc
fuente
fuente
Respuestas:
Considere lo que es un índice en SQL, y el índice es en realidad un trozo de memoria que apunta a otros trozos de memoria (es decir, punteros a filas). El índice se divide en páginas para que porciones del índice se puedan cargar y descargar de la memoria según el uso.
Cuando solicita un conjunto de filas, SQL usa el índice para encontrar las filas más rápidamente que el escaneo de tablas (mirando 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 manera, cuando solicita todas las filas que coinciden 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 intentar agrupar indexar una columna GUID es una mala idea: no intenta agrupar valores aleatorios.
Cuando indexa una columna de entero, 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 haya, esto se puede paginar de manera diferente. Si su consulta busca el índice que coincide con "1" y luego donde 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 la tabla escanea para encontrar el resto.
Entonces, lo que SQL realmente está haciendo es tratar de reducir el conjunto de trabajo (número de filas) sobre el que tiene que iterar.
Cuando indexa un campo de bits (o algún rango estrecho), solo reduce el conjunto de trabajo por el número de filas que coinciden con ese valor. Si tiene una pequeña cantidad de filas que coinciden, reduciría mucho su conjunto de trabajo. Para una gran cantidad de filas con una distribución 50/50, es posible que obtenga muy poca ganancia de rendimiento en comparación con mantener el índice actualizado.
La razón por la 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 la tabla es más rápido, o puede usar una clasificación, o puede organizar las páginas de memoria como quiera.
fuente
Me encontré con esta pregunta a través de otra. Suponiendo que su declaració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 como:
Esto creará un índice sustancialmente más pequeño que el optimizador es lo suficientemente inteligente para usar cuando ese es un predicado en su consulta.
fuente
yourBitColumn = @value
, el optimizador no puede determinar si el índice filtrado es utilizable.¿100 millones de registros y solo unos pocos tienen el campo de bits establecido en 1? Sí, creo que indexar el campo de bits definitivamente aceleraría la consulta de los registros bit = 1. Debe obtener el tiempo de búsqueda logarítmica del índice y luego tocar solo las pocas páginas con registros bit = 1. De lo contrario, tendría que tocar todas las páginas de la tabla de registros de 100 millones.
Por otra parte, definitivamente no soy un experto en bases de datos y podría estar perdiendo algo importante.
fuente
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 haga una cláusula WHERE con bit = 1, un escaneo completo de la tabla será aproximadamente 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 esa manera, ese índice solo almacenará la fila del 1%. Luego, hacer un DONDE bit = 0 simplemente permitirá 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 para comparar un índice completo en el bit .
fuente
Si bien no creo que indexaría SOLO una columna de bits por sí misma, es muy común incluir columnas de bits como parte de un índice compuesto.
Un ejemplo simple sería un índice en ACTIVE, LASTNAME en lugar de solo lastname, cuando su aplicación casi siempre busca clientes activos.
fuente
En caso de que no lo haya leído, Jason Massie escribió un artículo recientemente que discutía este mismo tema.
http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx
Editar: Ubicación del nuevo artículo: http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit
Wayback machine para la ubicación del artículo anteriormente "Nuevo": 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 que trata 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
máquina de retorno: http://web.archive.org/web/20150508115802/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
fuente
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 utilizar funciones de partición y puede filtrar los datos que van en un índice. La desventaja de las 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.
fuente
Como han dicho otros, querrás medir esto. No recuerdo dónde leí esto, pero una columna debe 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, entonces sabe que se utilizará su índice.
Su mejor curso de acción sería probar con una tabla SELECT * FROM básica DONDE BitField = 1; consulte y desarrolle lentamente la funcionalidad desde allí paso a paso hasta que tenga una consulta realista para su aplicación, examinando el plan de ejecución con cada paso para asegurarse de que la búsqueda de índice todavía se esté utilizando. Es cierto que no hay garantía de que este plan de ejecución se utilice en producción, pero es muy probable que así sea.
Puede encontrar alguna información en los foros de sql-server-performance.com y en el artículo de referencia
fuente
"Recuerdo haber leído en un momento que no vale la pena indexar un campo con cardinalidad baja (un número bajo de valores distintos)"
Eso porque SQL Server casi siempre encontrará más eficiente simplemente hacer un escaneo de tabla que leer el índice. Entonces, básicamente, su índice nunca se usará y es un desperdicio mantenerlo. Como han dicho otros, podría estar bien en un índice compuesto.
fuente
Si su objetivo es hacer que la consulta de registros donde el valor del campo de bits sea igual a '1' sea más rápida, puede probar una vista indexada de su tabla base que solo contiene registros donde su campo de bits es igual a '1'. En la edición empresarial, si una consulta puede utilizar una vista indexada en lugar de una tabla específica para mejorar el rendimiento de la consulta, utilizará la vista. En teoría, esto aumentaría la velocidad de las consultas seleccionadas que solo buscan registros con un valor de campo de bits de '1'.
http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
Todo esto supone que eres Microsoft SQL Server 2005 Enterprise. Lo mismo podría aplicarse a 2008, no estoy familiarizado con esa versión.
fuente
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 su tabla lo suficiente, debido al costo de mantener un índice. (costo> beneficio). Pero si el índice en su caso corta la mesa a la mitad, puede ganar algo pero poniéndolo sobre la mesa. Todo depende del tamaño / estructura exactos de su tabla y de cómo la esté utilizando (número de lecturas / escrituras).
fuente
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.
fuente
No puede indexar un campo de bits en SQL Server 2000, como se indicó en los Libros en pantalla en ese momento:
Sí, si solo tiene un puñado de filas, entre millones, un índice le ayudará. Pero si desea hacerlo en este caso, debe hacer que la columna a
tinyint
.Nota : Enterprise Manager no le permitirá crear un índice en una columna de bits. Si lo desea, aún puede crear manualmente un índice en una columna de bits:
Pero SQL Server 2000 en realidad no usará dicho índice, ejecutando una consulta donde el índice sería un candidato perfecto, por ejemplo:
En su lugar, SQL Server 2000 realizará una exploración de la tabla, actuando como si el índice ni siquiera existiera. Si cambia la columna a un tinyint, SQL Server 2000 hará una búsqueda de índice. Además, la siguiente consulta no cubierta:
Realizará una búsqueda de índice, seguida de una búsqueda de marcadores.
SQL Server 2005 tiene soporte limitado para índices en columnas de bits. Por ejemplo:
provocará una búsqueda de índice a través del índice de cobertura. Pero el caso no cubierto:
no provocará una búsqueda de índice seguida de una búsqueda de marcador, realizará un escaneo de tabla (o escaneo 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.
fuente
respuesta muy tardía ...
Sí, puede ser útil según el equipo de SQL CAT (actualizado, consolidado)
fuente
¿Es esta una consulta común? Puede valer la pena cuando busque el "puñado" de registros, pero no le ayudará mucho en las otras filas. ¿Existen otras formas de identificar los datos?
fuente
La cardinalidad es un factor, el otro es qué tan bien divide el índice sus datos. Si tiene alrededor de la mitad de los 1 y la mitad de los 0, entonces será de ayuda. (Suponiendo que ese índice es una mejor ruta para elegir que algún otro índice). Sin embargo, ¿con qué frecuencia inserta y actualiza? Agregar índices para el rendimiento de SELECT también perjudica el rendimiento de INSERT, UPDATE y DELETE, así que téngalo en cuenta.
Yo diría que si el 1 al 0 (o viceversa) no es mejor que el 75% al 25%, no se moleste.
fuente
medir el tiempo de respuesta antes y después y ver si vale la pena; en teoría, debería mejorar el rendimiento de las consultas que utilizan los campos indexados, pero realmente depende de la distribución de valores verdaderos / falsos y los otros campos involucrados en las consultas que le preocupan
fuente
Ian Boyd tiene razón cuando dice que no podría hacerlo a través de Enterprise Manager para SQL 2000 (vea su nota sobre cómo crearlo a través de T-SQL.
fuente
Debe ser inteligente aquí para consultar, debe conocer el valor de carga en su columna si la carga de verdadero es mayor en su sistema y desea verificar todos los valores verdaderos, escriba su consulta para verificar que no sea falso ... ayudará mucho , es solo un truco.
fuente