Je stocke des données de capteur dans une table SensorValues. La table et la clé primaire sont les suivantes:
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])
Pourtant, lorsque je sélectionne la valeur du capteur valide pour une heure précise, le plan d'exécution me dit qu'il fait une sorte. Pourquoi donc?
J'aurais pensé que depuis que je stocke les valeurs triés par la colonne Date, le tri ne se produirait pas. Ou est-ce parce que l'index n'est pas uniquement trié par la colonne Date, c'est-à-dire qu'il ne peut pas supposer que le jeu de résultats est trié?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Edit: puis-je faire cela à la place?
Puisque la table est triée DeviceID, Sensorid, date et je fais un [~ # ~] Sélectionnez [~ # ~ ~] Spécification d'un DeviceID et un Sensorid, le jeu de sortie doit déjà être trié par date de descente. Je me demande donc si la question suivante donnerait le même résultat dans tous les cas?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
Selon @catcall ci-dessous, l'ordre de tri n'est pas identique à l'ordre de stockage. C'est à dire. Nous ne pouvons pas supposer que les valeurs retournées sont déjà dans un ordre trié.
Modifier: J'ai essayé cette solution croix Appliquer, pas de chance
@Martin Smith a suggéré que j'essaierais d'appliquer mon résultat contre les partitions. J'ai trouvé un article de blog ( aligné des index non clusters sur la table partitionnée ) décrivant ce problème similaire et essayé la solution quelque peu similaire à ce que Smith a suggéré. Cependant, pas de chance ici, le temps d'exécution est à égalité avec ma solution d'origine.
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
Beaucoup de gens croient qu'un index en cluster garantit un trier ordre de sortie. Mais ce n'est pas ce que ça fait; Il garantit un stockage ordre sur disque.
Voir, par exemple, ce blog post et cette discussion plus longue .
Je spécule que le tri est nécessaire à cause d'un plan parallèle. Je base ceci sur un élément de blog dim et distant: mais j'ai trouvé ceci sur MSDN qui peut ou non justifier cela
Alors, essayez avec maxdop 1 et voyez ce qui se passe ...
Aussi allongé à @ SQL Kiwi's Blog Post sur simple conversation Sous "Opérateur d'échange", je pense. Et "dépendance DOP" ici
Fondamentalement, vous avez raison - car la clé principale est dans l'ordre "DeviceId, Sensorid, Date", les données de la clé ne sont pas triées par date, alors ne pouvez pas être utilisé. Si votre clé était dans une commande différente "Date, périphérique, Sensorid", les données de la clé volonté être triée par date, afin de pouvoir être utilisée ...