Dans SQL Server 2008, le type de date a été ajouté.
La conversion d' une datetime
colonne en date
est sargable et peut utiliser un index sur la datetime
colonne.
select *
from T
where cast(DateTimeCol as date) = '20130101';
L'autre option que vous avez est d'utiliser une plage à la place.
select *
from T
where DateTimeCol >= '20130101' and
DateTimeCol < '20130102'
Ces requêtes sont-elles également bonnes ou faut-il privilégier l'une ou l'autre?
sql-server
Mikael Eriksson
la source
la source
where cast(date_column as date) = 'value'
lorsque C # est similaire àwhere obj.date_column.Date == date_variable
.Réponses:
Le mécanisme derrière la sargabilité du casting à ce jour est appelé recherche dynamique .
SQL Server appelle une fonction interne
GetRangeThroughConvert
pour obtenir le début et la fin de la plage.De manière quelque peu surprenante, ce n'est pas la même plage que vos valeurs littérales.
Création d'un tableau avec une ligne par page et 1440 lignes par jour
Puis courir
La première requête a
1443
lu et la seconde2883
, il lit un jour supplémentaire puis le rejette contre un prédicat résiduel.Le plan montre que le prédicat de recherche est
Ainsi, au lieu de
>= '20130101' ... < '20130102'
le lire,> '20121231' ... < '20130102'
puis élimine toutes les2012-12-31
lignes.Le fait que les estimations de cardinalité ne soient pas aussi précises que dans le cas d’une interrogation de distance classique présente un autre inconvénient. Cela se voit dans une version modifiée de votre SQL Fiddle .
Les 100 lignes de la table correspondent maintenant au prédicat (avec des dates-heures distantes d'une minute le même jour).
La deuxième requête (plage) estime correctement que 100 correspondra et utilisera une analyse d'index en cluster. La
CAST( AS DATE)
requête estime à tort qu'une seule ligne correspondra et produit un plan avec des recherches de clé.Les statistiques ne sont pas complètement ignorées. Si toutes les lignes de la table ont la même chose
datetime
et si elles correspondent au prédicat (par exemple20130101 00:00:00
ou20130101 01:00:00
), le plan affiche une analyse d'index en cluster avec environ 31,6228 lignes.Donc, dans ce cas, il apparaît que l'estimation est dérivée de la formule ici .
Si toutes les lignes de la table ont la même chose
datetime
et si elles ne correspondent pas au prédicat (par exemple20130102 01:00:00
), alors le nombre de lignes estimé est égal à 1 et le plan contient des recherches.Dans les cas où la table a plusieurs
DISTINCT
valeurs, les lignes estimées semblent être les mêmes que si la requête cherchait exactement20130101 00:00:00
.Si l'histogramme des statistiques comporte un pas,
2013-01-01 00:00:00.000
l'estimation est basée sur leEQ_ROWS
(c'est-à-dire qu'elle ne tient pas compte des autres heures à cette date). Sinon, s'il n'y a pas d'étape, il semblerait que vous utilisiez lesAVG_RANGE_ROWS
étapes précédentes.Comme
datetime
avec une précision d'environ 3 ms dans de nombreux systèmes, il y aura très peu de valeurs de doublons réelles et ce nombre sera égal à 1.la source
TL;DR
partie avec quelques points avec des cas différents et préciser si, dans ce cas, la distribution à ce jour est-elle une bonne idée ou non?Je sais que cela a une longue réponse Great Answer® de Martin, mais je voulais ajouter quelques changements au comportement dans les nouvelles versions de SQL Server. Cela semble n'avoir été testé que jusqu'en 2008R2.
Avec les nouveaux USE HINT qui permettent d'effectuer une estimation du temps de cardinalité, nous pouvons voir quand les choses ont changé.
Utilisation de la même configuration que dans SQL Fiddle.
Nous pouvons tester les différents niveaux comme suit:
Les plans pour tout cela sont disponibles ici . Les niveaux de compatibilité 100 et 110 donnent tous les deux le plan de recherche clé, mais à partir du niveau de compatibilité 120, nous commençons à obtenir le même plan de balayage avec des estimations sur 100 lignes. Cela est vrai jusqu'au niveau 140.
L'estimation de la cardinalité pour les
>= '20130101', < '20130102'
plans reste à 100, ce qui était prévu.la source