Il s'agit d'une question dérivée de l' ordre de tri spécifié dans la clé primaire, mais le tri est exécuté sur SELECT .
@Catcall le dit au sujet de l'ordre de stockage (index clusterisé) et de l'ordre de sortie
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 .
J'ai lu l'article de blog de Hugo Kornelis et je comprends qu'un index ne garantit pas que le serveur SQL lit les enregistrements dans un ordre spécifique. Pourtant, j'ai du mal à accepter que je ne peux pas assumer cela pour mon scénario?
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])
Ma requête d'origine était la suivante:
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Mais je suggère que je pourrais aussi bien utiliser celui-ci (lire ci-dessous pour mon explication):
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
Comme vous pouvez le voir, mes lignes de table sont petites (16 octets) et je n'ai qu'un seul index, un cluster. Dans mon scénario, la table se compose de 100 000 000 d'enregistrements en ce moment (et cela augmentera très probablement dix fois).
Lorsque le serveur de base de données interroge cette table, il a deux façons de trouver mes lignes, soit il recherche la clé primaire et donc lit et renvoie mes valeurs en desc. ordre de date, ou il doit faire une analyse complète de la table. Ma conclusion est qu'une analyse complète de la table sur tous ces enregistrements sera beaucoup trop lente et le serveur de base de données cherchera donc toujours la table via sa clé primaire et retournera ainsi les valeurs triées parDate DESC
ORDER BY
dessus, alors vous savez que vous pouvez vous y fier. Voir # 3 iciORDER BY
clause est un gros coup de performance pour moi (lire l' autre question pour plus d'infos). J'ai une solution qui fonctionne pour l'instant, mais elle ne tiendra pas quand et si mon trafic augmente.ORDER BY
clause dans votre requête. Cela est vrai pour SQL Server , Oracle , MySQL et tout autre SGBDR auquel vous pouvez penser. Essayez autre chose et vous vous préparez pour une tasse surprise de FAIL.Réponses:
Permettez-moi d'essayer d'expliquer pourquoi vous ne devriez pas faire cela, pourquoi vous ne devriez jamais supposer qu'un produit SQL retournera un jeu de résultats dans un ordre spécifique, sauf si vous le spécifiez, quels que soient les indices - cluster ou non cluster, B-trees ou R-Trees ou kd-trees ou fractal-trees ou tout autre indice exotique utilisé par un SGBD.
Votre requête d'origine indique au SGBD de rechercher dans le
SensorValues
tableau, de trouver des lignes qui correspondent aux 3 conditions, de classer ces lignes par ordreDate
décroissant, de ne conserver que la première ligne de celles-ci et - enfin - de sélectionner et de renvoyer uniquement laSensorValue
colonne.Ce sont des ordres très spécifiques que vous avez donnés au SGBD et le résultat sera probablement le même à chaque fois que vous exécutez la requête (il y a une chance que ce ne soit pas le cas, si vous avez plus d'une ligne qui correspond aux conditions et qui ont les mêmes max
Date
mais différent,SensorValue
mais supposons pour le reste de la conversation qu'aucune ligne de ce type n'existe dans votre table).Le SGBD doit-il le faire, pour exécuter cette requête, de la façon exacte dont je le décris ci-dessus? Non, bien sûr que non et vous le savez. Il peut ne pas lire la table mais lire à partir d'un index. Ou il peut utiliser deux index s'il pense que c'est mieux (plus vite). Ou trois. Ou il peut utiliser un résultat mis en cache (pas SQL Server mais d'autres résultats de requête de cache de SGBD). Ou il peut utiliser une exécution parallèle une fois et non la prochaine fois qu'il s'exécute. Ou ... (ajoutez toute autre fonctionnalité qui affecte l'exécution et les plans d'exécution).
Ce qui est garanti cependant, c'est qu'il retournera exactement le même résultat, chaque fois que vous l'exécuterez - tant qu'aucune ligne n'est insérée, supprimée ou mise à jour.
Voyons maintenant ce que dit votre suggestion:
Cette requête indique au SGBD de rechercher la
SensorValues
table, de trouver des lignes qui correspondent aux 3 conditions, declasser ces lignes par ordre, de ne pas se soucier de l'ordre, de ne conserver qu'une seule ligne et - enfin - de sélectionner et de renvoyer uniquement laDate
décroissantSensorValue
colonne.Donc, il dit essentiellement la même chose que la première, sauf qu'il dit que vous ne voulez qu'un seul résultat qui correspond aux conditions et que vous ne vous souciez pas lequel .
Maintenant, pouvons-nous supposer qu'il donnera toujours le même résultat à cause de l'index clusterisé?
- S'il utilise cet index clusterisé à chaque fois, oui.
Mais l'utilisera-t-il?
- Non.
Pourquoi pas?
- Beacuse ça peut. L'optimiseur de requêtes est libre de choisir un chemin d'exécution à chaque fois qu'il exécute une instruction. Quelle que soit la voie qu'il juge appropriée à ce moment-là pour cette déclaration.
Mais l'utilisation de l'index cluster n'est-elle pas la manière la meilleure / la plus rapide d'obtenir des résultats?
- Non, pas toujours. Ce peut être la première fois que vous exécutez la requête. La deuxième fois, il peut utiliser un résultat mis en cache (si le SGBD possède une telle fonctionnalité, pas SQL Server * ). La 1000e fois, le résultat peut avoir été supprimé du cache et un autre résultat peut y exister. Disons que vous avez exécuté cette requête juste avant:
et le résultat mis en cache (à partir de la requête ci-dessus) en est un autre, différent, qui correspond toujours à vos conditions mais n'est pas le premier dans votre commande (souhaitée). Et vous avez dit au SGBD de ne pas se soucier de la commande.
OK, donc seul le cache peut affecter cela?
- Non, beaucoup d'autres choses aussi.
*: SQL Server ne met pas en cache les résultats des requêtes, mais l'édition Enterprise possède une fonctionnalité d' analyse avancée qui est un peu similaire dans la mesure où vous pouvez obtenir des résultats différents en raison de requêtes simultanées. Je ne sais pas exactement quand cela se produira. (Thnx @Martin Smith pour l'astuce.)
J'espère que vous êtes convaincu que vous ne devez jamais compter qu'une requête SQL retournera les résultats dans un ordre spécifique, sauf si vous le spécifiez. Et n'utilisez jamais
TOP (n)
sansORDER BY
, à moins bien sûr que vous vouliez juste n lignes dans le résultat et que vous ne vous souciez pas de celles qui sont retournées.la source