Tengo una pregunta sobre los índices de SQL Server. No soy un DBA y supongo que la respuesta es clara para aquellos de ustedes que sí lo son. Estoy utilizando SQL Server 2008.Orden de índice de SQL Server (campo de fecha y hora)
Tengo una tabla que es similar a lo siguiente (pero tiene más columnas):
CREATE TABLE [dbo].[Results](
[ResultID] [int] IDENTITY(1,1) NOT NULL,
[TypeID] [int] NOT NULL,
[ItemID] [int] NOT NULL,
[QueryTime] [datetime] NOT NULL,
[ResultTypeID] [int] NOT NULL,
[QueryDay] AS (datepart(day,[querytime])) PERSISTED,
[QueryMonth] AS (datepart(month,[querytime])) PERSISTED,
[QueryYear] AS (datepart(year,[querytime])) PERSISTED,
CONSTRAINT [PK_Results] PRIMARY KEY CLUSTERED
(
[ResultID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
Los campos importantes de aviso aquí están resultid, la clave primaria, y QueryTime la fecha y hora en que se produjo el resultado.
que también tienen el siguiente índice (entre otros):
CREATE NONCLUSTERED INDEX [IDX_ResultDate] ON [dbo].[Results]
(
[QueryTime] ASC
)
INCLUDE ([ResultID],
[ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
En una base de datos en la que tengo un millón de filas en la tabla, se utiliza el índice cuando se hace una consulta como:
select top 1 * from results where querytime>'2009-05-01' order by ResultID asc
En otra instancia de la misma base de datos, con 50 millones de filas, SQL Server decide no usar el índice, ya que hace un escaneo de índice en clúster que termina siendo terriblemente lento. (y la velocidad depende de la fecha). Incluso si uso consejos de consulta para hacer que use IDX_ResultDate, todavía es un poco lento y pasa el 94% de su tiempo ordenando por ResultID. Pensé que al crear un índice con ResultID y QueryTime como columnas ordenadas en el índice, podría acelerar mi consulta.
por lo tanto crean los siguientes:
CREATE NONCLUSTERED INDEX [IDX_ResultDate2] ON [dbo].[Results]
(
[QueryTime] ASC,
[ResultID] ASC
)
INCLUDE ([ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
que supone que utilizaría en primer lugar el tipo de QueryTime para encontrar los resultados coincidentes, que ya se puede ordenar por resultid. Sin embargo, este no es el caso ya que este índice no cambia nada en el rendimiento sobre el existente.
entonces intentado el siguiente índice:
CREATE NONCLUSTERED INDEX [IDX_ResultDate3] ON [dbo].[Results]
(
[ResultID] ASC,
[QueryTime] ASC
)
INCLUDE ([ItemID],
[TypeID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
Éste produce el resultado deseado. Parece regresar en tiempo constante (una fracción de segundo).
Sin embargo, estoy desconcertado por qué IDX_ResultDate3 funciona bien, mientras que IDX_ResultDate2 no.
Supongo que una búsqueda binaria en una lista ordenada de QueryTime seguida por la búsqueda en el primer resultado en su lista secundaria de ResultIDs es la forma más rápida de obtener el resultado. (De ahí mi orden de clasificación inicial).
Pregunta adicional: ¿Debo crear una columna persistente con la parte de la fecha de QueryTime e indexar en su lugar (ya tengo tres columnas persistentes como se puede ver arriba)?
Muy buena explicación. Entiendo ahora. Veré si puedo rediseñar la aplicación para usar el tipo QueryTime. –