2009-08-05 5 views
7

Tengo una tabla A que tiene fecha de inicio y fecha de finalización como 2 columnas de fecha y hora, además de algunas otras columnas. Tengo otra tabla B que tiene una columna de fecha y hora llamada columna de fechas. Esto es en SQL Server 2005.La forma más rápida para esta consulta (Cuál es la mejor estrategia) dado un rango de fechas

Aquí la pregunta: ¿Cómo definir mejor los índices, etc obtener la siguiente:

select .... 
from A , B 
where A.startDate >= B.dates 
    and A.endDate < B.dates 

Ambas tablas tienen varios miles de registros.

Respuesta

-5

Si necesita optimizar intente ejecutar esta consulta en el Analizador de consultas.

0

todas las versiones de SQL Server 2000, 2005, 2008 tiene un programa llamado Base de Datos asesor de ajuste cuando se ejecuta alguna consulta que le dice lo índices es necesario agregar para obtener la consulta más rápido Best Regards, Iordan

0

Necesita 3 índices A.startDate, B.dates y A.endDate, puede ser índice (A.endDate + A.startDate) también es bueno. No tengo detalles sobre otras columnas y propósitos para estas tablas, pero reviso la posibilidad de usar el índice agrupado.

En cualquier caso utilizar la opción de "plan de ejecución" para tomar la decisión entre todas estas variantes, porque mi sugerencia es demasiado general

0

La siguiente secuencia de comandos mostrará una lista de posibles índices que faltan (es posible filtrar la declaración de t.name).

SELECT  t.name AS 'affected_table', 
      'Create NonClustered Index IX_' + t.name + '_missing_' + CAST(ddmid.index_handle AS VARCHAR(10)) + ' On ' + ddmid.STATEMENT + ' (' + ISNULL(ddmid.equality_columns, '') + 
      CASE 
         WHEN ddmid.equality_columns IS NOT NULL 
          AND ddmid.inequality_columns IS NOT NULL 
         THEN ',' 
         ELSE '' 
      END + ISNULL(ddmid.inequality_columns, '') + ')' + ISNULL(' Include (' + ddmid.included_columns + ');', ';') AS sql_statement, 
      ddmigs.user_seeks, 
      ddmigs.user_scans, 
      CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) AS 'est_impact', 
      ddmigs.last_user_seek 
FROM  sys.dm_db_missing_index_groups  AS ddmig 
INNER JOIN sys.dm_db_missing_index_group_stats AS ddmigs 
ON   ddmigs.group_handle = ddmig.index_group_handle 
INNER JOIN sys.dm_db_missing_index_details AS ddmid 
ON   ddmig.index_handle = ddmid.index_handle 
INNER JOIN sys.tables AS t 
ON   ddmid.OBJECT_ID = t.OBJECT_ID 
WHERE  ddmid.database_id = DB_ID() 
     AND CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) > 100 
ORDER BY CAST((ddmigs.user_seeks + ddmigs.user_scans) * ddmigs.avg_user_impact AS INT) DESC; 
-1

Simplemente agregaría un índice agrupado en B.dates. Si agrega índices en startDate y endDate, no comprará nada porque de todos modos obtendrá escaneos de índice en A. El índice agrupado en B te da una búsqueda de índice en B al menos. Un Escaneo de tabla y Escaneo de índice son lo mismo, así que no tiene sentido agregar índices para sacar la palabra Escaneo de tabla de su plan de ejecución :)

Me burlaría de algunas maneras o vería si puede rehacer su consulta para no requerir un escaneo de tabla en A, que supongo que no es realmente posible.

+0

"Una exploración de tabla y exploración de índice son lo mismo"? No lo creo, a menos que te refieras cuando el índice tiene todas las columnas en la tabla. Dudo mucho que sus tablas solo tengan las columnas mencionadas en ellas. – ongle

+0

Sí, son lo mismo. Un análisis de índice recupera cada fila de una tabla, mientras que una búsqueda no lo hace. Un escaneo de tabla (o escaneo de índice) donde no hay otro índice agrupado en la tabla le da el peor desempeño. – Jon

+0

Un análisis de índice recupera cada "fila" del índice, no de la tabla. Una exploración de índice es mejor que una exploración de tabla simplemente porque un índice normalmente tiene menos columnas en ella que la tabla, lo que da como resultado más "filas" por lectura. Pero estamos de acuerdo en que los escaneos son malos y deben evitarse. – ongle

0

Se necesita un poco más de información. ¿Cuántas otras columnas hay en las tablas? ¿Estas tablas existentes con muchas consultas ya van en contra de ellas, o todas las tablas nuevas? ¿Qué tipo de problema de rendimiento estás viendo que te lleve a hacer la pregunta?

Supongo que las tres columnas NO SON NULAS (no solo para la sintaxis de la consulta, sino también para la utilidad del índice).

Comenzaría con un índice compuesto en A.startDate + A.endDate, y otro índice en B.dates (pero esto probablemente no sea necesario). A menos que estas fechas sean el objetivo principal de las tablas, evitaría crear índices agrupados en estas columnas. Esto es doblemente cierto si estas tablas son tablas existentes con otras consultas ejecutándose contra ellas. Las consultas anteriores pueden escribirse esperando los índices agrupados existentes.

2

He trabajado en dos empresas (ambas haciendo sistemas de administración de tiempo y asistencia) que tienen muchas veces con las columnas startDate y endDate. En mi experiencia, no hay buenos índices que siempre funcione con rangos de fecha.

Pruebe índices como (fecha de inicio de sesión, fecha de finalización) y (-endFecha, fecha de inicio) para ver si ayudan, mucho depende de cómo son los datos en la tabla. MI.g si tiende a tener muchas filas antiguas con un endDate antes de las fechas que está buscando, puede ser útil forzar a Sql a usar un índice basado en (endDate, startDate).

También intente utilizar un índice que cubra todas las columnas que están en su instrucción "where", por lo que sql no necesita leer la tabla principal hasta que no haya resuelto qué filas devolver.

Usted puede tiene que utilizar sugerencias de índice, ya que es poco probable que el procesador de consultas sabe lo suficiente sobre los datos para hacer una buena elección de los índices - este es uno de muy pocos casos en que he tenido que considerar indicios de índice.

Ampliación de los datos, por lo que tiene una tabla que contiene (fecha, remado) con una fila para cada fecha dentro del rango de fechas puede necesario. Sin embargo, mantener actualizada la tabla de "índice" es un problema.

Si usted sabe que algunos de sus rangos de fechas no se solapan, echar un vistazo a Using CROSS APPLY to optimize joins on BETWEEN conditions (registros de enfermedad por ejemplo, una de los empleados no se les puede permitir a superponerse)

Al final del día, si sólo tiene varios miles de registros, un escaneo completo de tabla no es tan malo.

Quassnoi subjects using SPATIAL indexes, no tengo experiencia con "abusar" de los índices espaciales de esta manera, pero creo que vale la pena intentarlo. Sin embargo, tenga mucho cuidado si debe multiplicar los proveedores de bases de datos múltiples, ya que el índice espacial es bastante nuevo. También es posible que aún necesite las columnas de fecha para herramientas de informes, etc.

(Tarde o temprano tendrá que ser capaz de encontrar todas las filas que se superponen a un rango de fechas, entonces será aún más difícil obtener índices que arrojen buenos resultados).

0

me gustaría ir con este

CREATE CLUSTERED INDEX IX_DateRange ON dbo.A 
    (
    StartDate, 
    EndDate DESC 
    ) 
GO 
7

actualización:

Lee este artículo en mi blog para la estrategia de indexación eficiente para su búsqueda usando las columnas calculadas:

La idea principal es que sólo calcula redondeada length y startDate para usted rangos y luego buscamos para ellos el uso de condiciones de igualdad (que son buenos para B-Tree índices)


En MySQL y en SQL Server 2008 puede usar los índices SPATIAL (R-Tree).

Son especialmente buenos para las condiciones como "seleccionar todos los registros con un punto determinado dentro del rango del registro", que es solo tu caso.

almacenar los start_date y end_date como el principio y el final de un LineString (convirtiéndolos a UNIX marcas de tiempo de otro valor numérico), índice con un índice de SPATIAL y la búsqueda de todos estos LineString s cuyo cuadro de límite mínimo (MBR) contiene el valor de fecha en cuestión, usando MBRContains.

Ver esta entrada en mi blog acerca de cómo hacer esto en MySQL:

y una visión general del rendimiento breve para SQL Server:

Se puede aplicar la misma solución para buscar un valor IP dado en rangos de red almacenados en la base de datos.

Esta tarea, junto con su consulta, es otro ejemplo frecuente de dicha condición.

Normal B-Tree los índices no son buenos si los rangos se pueden superponer.

Si no pueden (y lo sabes), puede utilizar la solución brillante propuesto por @AlexKuznetsov

También tenga en cuenta que este rendimiento de las consultas depende totalmente de su distribución de datos.

Si usted tiene un montón de registros en B y pocos registros en A, usted podría construir un índice en B.dates y dejar que el TS/CIS en A marcha.

Esta consulta siempre leerá todas las filas desde A y usará Index Seek en B.dates en un bucle anidado.

Si sus datos se distribuyen de otra forma, yo. mi. usted tiene un montón de filas en A pero pocos en B, y los rangos son generalmente cortos, entonces se podría rediseñar sus mesas un poco:

A 

start_date interval_length 

, crear un índice compuesto en A (interval_length, start_date)

y utilizar esta consulta :

SELECT * 
FROM (
     SELECT DISTINCT interval_length 
     FROM a 
     ) ai 
CROSS JOIN 
     b 
JOIN a 
ON  a.interval_length = ai.interval_length 
     AND a.start_date BETWEEN b.date - ai.interval_length AND b.date 
+0

Este es el primer buen motivo que he visto para hacer que el software dependa de SQL Server 2008 (en lugar de 2005) –

+0

No sé cómo combinar el índice espacial con otros tipos de índice, por ejemplo "donde department = 123 y SickLeave OVERLAPS WorldCub" –

+0

'@ Ian': en' SQL Server', los índices se usarán separados y luego se combinarán usando un método de fusión apropiado (muy probablemente 'HASH MATCH') – Quassnoi

Cuestiones relacionadas