Estoy almacenando datos del sensor en una tabla SensorValues . La tabla y la clave primaria son las siguientes:
CREATE TABLE [dbo].[SensorValues](
[DeviceId] [int] NOT NULL,
[SensorId] [int] NOT NULL,
[SensorValue] [int] NOT NULL,
[Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED
(
[DeviceId] ASC,
[SensorId] ASC,
[Date] DESC
) WITH (
FILLFACTOR=75,
DATA_COMPRESSION = PAGE,
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [MyPartitioningScheme]([Date])
Sin embargo, cuando selecciono el valor del sensor válido por un tiempo específico, el plan de ejecución me dice que está haciendo una especie. ¿Porqué es eso?
Pensé que, dado que almaceno los valores ordenados por la columna Fecha, la clasificación no se produciría. ¿O es porque el índice no está ordenado únicamente por la columna Fecha, es decir, no puede suponer que el conjunto de resultados está ordenado?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Editar: ¿Puedo hacer esto en su lugar?
Dado que la tabla está ordenada DeviceId, SensorId, Date y hago un SELECT especificando solo un DeviceId y un SensorId , el conjunto de salida ya debería estar ordenado por Date DESC . Entonces, me pregunto si la siguiente pregunta arrojaría el mismo resultado en todos los casos.
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
Según @Catcall a continuación, el orden de clasificación no es el mismo que el orden de almacenamiento. Es decir, no podemos suponer que los valores devueltos ya están en un orden ordenado.
Editar: he probado esta solución CROSS APPLY, no tuve suerte
@ Martin Smith sugirió que intentara APLICAR EXTERIORMENTE mi resultado contra las particiones. Encontré una publicación de blog ( índices alineados no agrupados en una tabla particionada ) que describe este problema similar y probé una solución algo similar a lo que Smith sugirió. Sin embargo, no tuve suerte aquí, el tiempo de ejecución está a la par con mi solución original.
WITH Boundaries(boundary_id)
AS
(
SELECT boundary_id
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
UNION ALL
SELECT max(boundary_id) + 1
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
),
Top1(SensorValue)
AS
(
SELECT TOP 1 d.SensorValue
FROM Boundaries b
CROSS APPLY
(
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND "Date" < 1339225010
AND $Partition.PF(Date) = b.boundary_id
ORDER BY Date DESC
) d
ORDER BY d.Date DESC
)
SELECT SensorValue
FROM Top1
fuente
Respuestas:
Para una tabla no particionada obtengo el siguiente plan
Hay un solo predicado de búsqueda en
Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010
.Lo que significa que SQL Server puede realizar una búsqueda de igualdad en las dos primeras columnas y luego comenzar una búsqueda de rango a partir de
1339225010
y ordenadaFORWARD
(como se define el índice con[Date] DESC
)El
TOP
operador dejará de solicitar más filas de la búsqueda después de que se emita la primera fila.Cuando creo el esquema de partición y la función
Y complete la tabla con los siguientes datos
El plan en SQL Server 2008 tiene el siguiente aspecto.
El número real de filas emitidas por la búsqueda es
500
. El plan muestra buscar predicadosIndicando que está utilizando el enfoque de omisión de exploración descrito aquí
Este plan es un plan en serie y, por lo tanto, para la consulta específica que tiene, parece que si SQL Server se asegurara de que procesara las particiones en orden descendente,
date
el plan original con elTOP
todavía funcionaría y podría detener el procesamiento después de que la primera fila coincidente fuera encontrado en lugar de continuar y generar los 499 partidos restantes.De hecho, parece que el plan para 2005 toma ese enfoque
No estoy seguro de si es sencillo obtener el mismo plan en 2008 o tal vez necesitaría un
OUTER APPLY
encendidosys.partition_range_values
para simularlo.fuente
Mucha gente cree que un índice agrupado garantiza un orden de clasificación en la salida. Pero eso no es lo que hace; garantiza una orden de almacenamiento en disco.
Vea, por ejemplo, esta publicación de blog y esta discusión más larga .
fuente
Estoy especulando que el SORT es necesario debido a un plan paralelo. Baso esto en un artículo de blog tenue y distante: pero encontré esto en MSDN que puede o no justificar esto
Entonces, intente con MAXDOP 1 y vea qué sucede ...
También insinuado en la publicación de blog de @sql kiwi en Simple Talk en "Operador de intercambio", creo. Y "dependencia DOP" aquí
fuente
date
antes. Ahora tengo y parece que la partición es la culpable de que 2005 se comporte mejor para esta consulta en particular.Básicamente tiene razón: dado que la clave principal está en el orden "DeviceId, SensorId, Date", los datos en la clave no están ordenados por fecha, por lo que no se pueden usar. Si su clave estaba en un orden diferente "Fecha, DeviceId, SensorId", entonces los datos en la clave se ordenarían por fecha, por lo que podrían usarse ...
fuente