2011-01-31 22 views
5

Tengo una tabla que contiene casi 850,000,000 de filas.Consulta sencilla de indexación en una gran base de datos

La tabla tiene los siguientes campos:

[ID] [bigint] IDENTITY(1,1) NOT NULL, 
[D1] [int] NOT NULL, 
[D2] [int] NOT NULL, 
[D3] [int] NOT NULL, 
[D4] [int] NOT NULL, 
[D5] [int] NOT NULL, 
[D6] [int] NOT NULL, 
[D7] [int] NOT NULL, 
[D8] [int] NOT NULL, 
[D9] [int] NOT NULL, 
[A] [int] NOT NULL, 
[Hb] [bit] NOT NULL, 

Todos mis consultas de esta tabla son exactamente lo mismo -

Select [D1-D9], [A] Where [Hb] = 0 AND [D1] <> x AND [D2] <> y AND [D3] = z,

etc ....

Cada consulta se SIEMPRE consulte TODOS los campos [D1-D9] y siempre solicite [Hb] = 0

Ejemplo de consulta:

SELECT [D1], [D2], [D3], [D4], [D5], [D6],[D7], [D8],[D9], [A] 
    from [myTable] 
WHERE [D1] <> 8 AND [D2] <> 2 AND [D3] <> 5 AND [D4] = 8 AND [D5] = 2 
    AND [D6] = 5 AND [D7] = 5 AND [D8] = 3 AND [D9] = 4 AND [A] = 0 AND [Hb] = 0 

¿Cómo debo indexar esta tabla para obtener los resultados más rápidos?

Muchas gracias

+0

¿Qué proporción de filas tiene hb = 0 y Dx igual a cada número? – Mark

+0

¿Cuál es la distribución de valores para las columnas? ¿Los valores se actualizan con frecuencia? ¿Alguna de las columnas (además de la columna de ID) tiene valores incrementales (y, por lo tanto, será candidata para un índice agrupado)? ¿Hay algún patrón en la forma de consultar los datos? Si pudieras darnos alguna información de dominio, eso también nos ayudaría a darte una respuesta. –

+0

La tabla está ordenada por d1, d2, d3, ...- d9 ejemplo: primera fila - de d1 a d9: 1, 1, 1, 1, 1, 1, 1, 1. Segunda fila: 1, 1, 1, 1, 1, 1, 1, 1, 2. ... y así sucesivamente ... en este momento, el índice agrupado es ID. La tabla nunca actualizará – Shay

Respuesta

0

Si el algoritmo es determinista (es decir, A = f (d1, d2, d3 ... D9)) a continuación, sus columnas D combinados con Hb constituyen una clave. Intenta crear un índice compuesto agrupado en todas las columnas D y Hb, particionando en Hb para un pequeño aumento de velocidad. También puede considerar abandonar el campo ID.

EDITAR: Acabo de darme cuenta de que me había perdido las <> condiciones. Como otros han mencionado, esto hace las cosas mucho más difíciles. Lo que realmente quiere usar aquí es un índice de mapa de bits, pero AFAIK SQL Server no los tiene. Es probable que deba confiar en los índices de columna individuales que juegan muy bien juntos.

+0

Sí, el algoritmo es determinista. ¿Puedes darme un ejemplo para el índice? ¿Qué campos debería tener, qué debería incluir el índice() (si existe)? – Shay

+0

La forma más simple de hacerlo sería CREAR ÍNDICE CLASIFICADO EN Mytable (D1, D2, D3, D4, D5, D6, D7, D8, D9, Hb); si eso funciona bien, entonces considere dividirlo. Sin embargo, antes de hacer esto, deberá soltar el índice agrupado existente en la ID. – dataduck

0

En primer lugar de todas las consultas con las condiciones como "donde X <> 8" puede hacer que cualquier índice inútil (que puede depender de su propio motor DB.

Es más seguro para cambiar esto desde

SELECT [D1], [D2], [D3], [D4], [D5], [D6],[D7], [D8],[D9], [A] 
    from [myTable] 
WHERE [D1] <> 8 AND [D2] <> 2 AND [D3] <> 5 AND [D4] = 8 AND [D5] = 2 
    AND [D6] = 5 AND [D7] = 5 AND [D8] = 3 AND [D9] = 4 AND [A] = 0 AND [Hb] = 0 

a algo más parecido a esto:.

SELECT [D1], [D2], [D3], [D4], [D5], [D6],[D7], [D8],[D9], [A] 
    from [myTable] 
WHERE ([D1] < 8 or [D1] > 8) 
     AND ([D2] < 2 or [D2] > 2) 
     AND ([D3] < 5 or [D3] > 5) 
     AND [D4] = 8 AND [D5] = 2 AND [D6] = 5 AND [D7] = 5 AND [D8] = 3 
     AND [D9] = 4 AND [A] = 0 AND [Hb] = 0 
+0

'OR' o' <> 'no importará – gbn

4

lo mejor que puede hacer es tener su índice de hacer comprobaciones de igualdad primero seguido de una búsqueda no igualdad residual es decir, = antes de <>.

Reorganización de la cláusula WHERE:

WHERE 
--Equality 
D4 = 8 AND D5 = 2 AND D6 = 5 AND D7 = 5 AND D8 = 3 AND D9 = 4 AND A = 0 
--in the middle  
AND Hb = 0 
--Non-Equality 
D1 <> 8 AND D2 <> 2 AND D3 <> 5 

Así, en primer proyecto es la siguiente:

CREATE .. INDEX ... ON (D4, D5, D6, D7, D8, D9, A, Hb, D1, D2, D3) 

El orden de D4-D9 debe basarse en la selectividad. Los números más altos primero. Hb siempre debe ir pasado en las columnas de igualdad porque es poco

SELECT 
    COUNT(DISTINCT D4) AS D4COunt, 
    COUNT(DISTINCT D5) AS D5COunt, 
    COUNT(DISTINCT D6) AS D6COunt, 
    COUNT(DISTINCT D7) AS D7COunt, 
    COUNT(DISTINCT D8) AS D8COunt, 
    COUNT(DISTINCT D9) AS D9COunt, 
    COUNT(DISTINCT A) AS ACOunt 
FROM 
    Mytable 

Finalmente, esto puede ser agrupado o no agrupado. Si no tiene otros índices o no tiene FK, consideraría convertirlo en el PK agrupado.De lo contrario, basta con crear una clave sustituta agrupado y hacer que este índice no agrupado

Editar:

Un artículo que (esperemos) explica por qué es importante el orden de columnas para los índices de columna Mulitple: Craig Freedman's Seek Predicates. Y su Scans and Seeks demasiado

Edit2:

me preguntaron si la = antes <> están en las mismas columnas: al parecer "sí". El comentario de OP a esta respuesta dice "no", así que todo lo que he dicho aquí no tiene sentido

La respuesta de las intersecciones de índice sugeridas por Damien_The_Unbeliever para tratar de evitar esta combinación de igualdad/no-igualdad.

+0

¿Por qué es que debe hacer los controles de igualdad antes de los controles de no igualdad, tengo curiosidad? – Kane

+0

@Kane: buscarán/combinarán. <> significa que debe verificar la ausencia de igualdad = un escaneo. – gbn

+0

Cambié la consulta a have = before <>. En cuanto al índice, cada consulta es diferente de la otra. Por ejemplo, la primera consulta puede ser "DONDE D4 = 8" y la otra puede ser "DONDE D4 <> 8". – Shay

2

Puede encontrar (si las pruebas de igualdad/desigualdad individuales son diferentes para las diez columnas en cada consulta) que lo mejor que puede hacer es crear un índice estrecho en cada columna individualmente y esperar que el optimizador aplique index intersection , donde usará los índices en cada columna donde tenga sentido hacerlo.

+0

Intenté hacerlo, pero el servidor sql no usó esos índices – Shay

+0

@Shay; en ese caso, todo lo que puedo sugerir es lanzar hardware hasta que el rendimiento sea aceptable. –

0

Básicamente, debe crear un índice compuesto iniciado por columna con comprobación de igualdad. Entonces, en su caso, es natural usar [Hb] como el primer componente ya que usted indicó que [Hb] se verificará con igualdad. Los siguientes elementos del índice son [D *], seguida de [A]

create index IXC_MyTable1 on Mytable(Hb, D1, D2, D3, D4, D5, D6, D7, D8, D9, A) 

En el segundo pensamiento, se puede emplear una indexación parcial y dejar que el PP haga un recorrido de índice rápido (CMIIW) a la tabla para verificar otros valores En este caso, debe incluir Id como el último elemento del índice. Por ejemplo:

create index IXC_MyTable__D123 on Mytable(Hb, D1, D2, D3, Id) 
create index IXC_MyTable__D456 on Mytable(Hb, D4, D5, D6, Id) 
create index IXC_MyTable__D789 on Mytable(Hb, D7, D8, D9, Id) 

La consulta utilizará índice IXC_MyTable__D123 cuando se utiliza cheques de igualdad en Hb, D1, D2, y D3; y así.

2

Extendiendo @gbn's la respuesta.

Para una tabla de este tamaño, definitivamente necesita un índice que cubra todas las columnas seleccionadas.

Sin embargo, para cada columna debe decidir si desea que sea una columna clave o una columna incluida en el índice.

Para ello, ejecute esta consulta:

SELECT SUM(CASE D1 WHEN 8 THEN 0 ELSE 1 END)/COUNT(*) AS D1Card, 
     SUM(CASE D2 WHEN 2 THEN 0 ELSE 1 END)/COUNT(*)/COUNT(DISTINCT D2) AS D2Card, 
     SUM(CASE D3 WHEN 5 THEN 0 ELSE 1 END)/COUNT(*)/COUNT(DISTINCT D3) AS D3Card, 
     SUM(CASE d4 WHEN 8 THEN 1 ELSE 0 END)/COUNT(DISTINCT D4) AS D4Card, 
     SUM(CASE d5 WHEN 2 THEN 1 ELSE 0 END)/COUNT(DISTINCT D5) AS D5Card, 
     SUM(CASE d6 WHEN 5 THEN 1 ELSE 0 END)/COUNT(DISTINCT D6) AS D6Card, 
     SUM(CASE d7 WHEN 5 THEN 1 ELSE 0 END)/COUNT(DISTINCT D7) AS D7Card, 
     SUM(CASE d8 WHEN 3 THEN 1 ELSE 0 END)/COUNT(DISTINCT D8) AS D8Card, 
     SUM(CASE d9 WHEN 4 THEN 1 ELSE 0 END)/COUNT(DISTINCT D9) AS D9Card, 
     SUM(CASE a WHEN 0 THEN 1 ELSE 0 END)/COUNT(DISTINCT A) AS ACard, 
     SUM(CASE Hb WHEN 0 THEN 1 ELSE 0 END)/COUNT(DISTINCT Hb) AS HbCard 
FROM Mytable 

Debe crear una lista de las columnas selectivas menos avanzados (aquellos con los más altos valores de *Card), que (junto) comprenden más de 25% de sus registros.

Say, el gráfico de la selectividad de las columnas es el siguiente:

Column Selectivity Cumulative selectivity 
D4  0.96   0.96 
D8  0.87   0.84 
D9  0.85   0.70 
D7  0.72   0.51 
D6  0.65   0.33 -- here 
D5  0.20   0.07 
A  0.02   0.00 
Hb  0.01   0.00 

Esto significa que las condiciones en las columnas d4, d8, d9, d7, d6 juntos coinciden sobre 33% de sus registros.

En este caso, no hay necesidad de usarlos como columnas clave. Debe crear un índice en las otras columnas selectivas e incluir las no selectivas en el índice.

CREATE INDEX ix_mytable_filter ON (Hb, A, D5) INLCUDE (D1, D2, D3, D4, D6, D7, D8, D9) 

Las columnas con el filtro no igualdad siempre van a la sección INCLUDE.

Tenga en cuenta que solo mejorará la consulta actual, con los valores dados de los filtros. Si sus filtros son arbitrarios, deberá usar todas las columnas con filtro de igualdad como las claves del índice.

También puede ser que las condiciones como [D1] <> 8 involucren números mágicos, y hay pocos registros que cumplan esta condición.

En este caso, se puede añadir una columna calculada en la definición de la tabla:

ALTER TABLE mytable ADD d1_ne_8 AS CASE D1 WHEN 8 THEN 0 ELSE 1 END 

y añadir esta expresión para el índice (con respecto a las reglas anteriores).

Si hace esto, tendrá que usar d1_ne_8 = 1 en lugar de d1 <> 8.

Cuestiones relacionadas