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 période spécifique, le plan d'exécution me dit qu'il fait un tri. Pourquoi donc?
J'aurais pensé que puisque je stocke les valeurs triées 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?
Étant donné que la table est triée DeviceId, SensorId, Date et que je fais un SELECT spécifiant un seul DeviceId et un SensorId , l'ensemble de sortie doit déjà être trié par Date DESC . 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 le même que l'ordre de stockage. C'est-à-dire que nous ne pouvons pas supposer que les valeurs retournées sont déjà dans un ordre trié.
Edit: j'ai essayé cette solution CROSS APPLY, pas de chance
@Martin Smith m'a suggéré d'essayer D'APPLIQUER MON RÉSULTAT contre les partitions. J'ai trouvé un article de blog ( index non alignés alignés sur une table partitionnée ) décrivant ce problème similaire et j'ai 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
Réponses:
Pour une table non partitionnée, j'obtiens le plan suivant
Il existe un seul prédicat de recherche
Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010
.Cela signifie que SQL Server peut effectuer une recherche d'égalité sur les deux premières colonnes, puis commencer une recherche de plage à partir de
1339225010
et ordonnéeFORWARD
(comme l'index est défini avec[Date] DESC
)L'
TOP
opérateur arrêtera de demander plus de lignes à la recherche après l'émission de la première ligne.Quand je crée le schéma de partition et la fonction
Et remplissez le tableau avec les données suivantes
Le plan sur SQL Server 2008 se présente comme suit.
Le nombre réel de lignes émises par la recherche est
500
. Le plan montre rechercher des prédicatsIndiquant qu'il utilise l' approche de saut de balayage décrite ici
Ce plan est un plan série et donc pour la requête spécifique que vous avez, il semble que si SQL Server s'est assuré qu'il a traité les partitions dans l'ordre décroissant,
date
le plan d'origine avec leTOP
fonctionnerait toujours et pourrait arrêter le traitement après la première ligne correspondante. trouvé plutôt que de continuer et de produire les 499 matches restants.En fait, le plan pour 2005 semble adopter cette approche
Je ne sais pas s'il est simple d'obtenir le même plan pour 2008 ou peut-être aurait-il besoin d'un
OUTER APPLY
onsys.partition_range_values
pour le simuler.la source
Beaucoup de gens pensent qu'un index clusterisé garantit un ordre de tri sur la sortie. Mais ce n'est pas ce qu'il fait; il garantit un ordre de stockage sur disque.
Voir, par exemple, cet article de blog et cette discussion plus longue .
la source
Je suppose que le SORT est nécessaire en raison du plan parallèle. Je base cela sur un article de blog sombre et distant: mais je l'ai trouvé sur MSDN qui peut ou non justifier cela
Alors, essayez avec MAXDOP 1 et voyez ce qui se passe ...
J'ai également fait allusion dans le blog de @sql kiwi sur Simple Talk sous "Exchange Operator" je pense. Et "dépendance DOP" ici
la source
date
avant. Maintenant, j'ai et semble être le partitionnement est le coupable avec 2005 se comportant peut-être mieux pour cette requête particulière.Fondamentalement, vous avez raison - puisque la clé primaire est dans l'ordre "DeviceId, SensorId, Date", les données de la clé ne sont pas triées par date, elles ne peuvent donc pas être utilisées. Si votre clé était dans un ordre différent "Date, DeviceId, SensorId", les données de la clé seraient triées par date, donc pourraient être utilisées ...
la source