J'ai un champ SQL datetime
dans une très grande table. Il est indexé et doit être interrogé.
Le problème est que SQL stocke toujours le composant d'heure (même s'il est toujours minuit), mais les recherches sont au jour plutôt qu'à l'heure.
declare @dateVar datetime = '2013-03-11;
select t.[DateColumn]
from MyTable t
where t.[DateColumn] = dateVar;
Ne retournera rien, car le t.[DateColumn]
inclut toujours une composante temporelle.
Ma question est quelle est la meilleure façon de contourner cela?
Il semble y avoir deux principaux groupes d'options:
Créez une deuxième variable à l'aide de dateadd
et utilisez un between ... and
ou >= ... and ... <=
.
Convertissez le t.[DateColumn]
dans un composant de date uniquement - je pense que cela entraînera l'ignorance de tout index.
Les deux semblent très compliqués - je ne veux pas vraiment faire de comparaison de plage ou scanner la table.
Y a-t-il une meilleure façon?
Si l'une de ces options est toujours optimale, comment et pourquoi?
La conversion en DATE
ou l'utilisation d'une plage de dates ouverte dans tous les cas donnera les meilleures performances. Pour info, les conversions à ce jour à l'aide d'un indice sont les plus performantes. Plus de tests sur différentes techniques dans l'article: Quel est le moyen le plus efficace pour couper le temps à partir de datetime? Publié par Aaron Bertrand
De cet article:
DECLARE @dateVar datetime = '19700204';
-- Quickest when there is an index on t.[DateColumn],
-- because CONVERT can still use the index.
SELECT t.[DateColumn]
FROM MyTable t
WHERE = CONVERT(DATE, t.[DateColumn]) = CONVERT(DATE, @dateVar);
-- Quicker when there is no index on t.[DateColumn]
DECLARE @dateEnd datetime = DATEADD(DAY, 1, @dateVar);
SELECT t.[DateColumn]
FROM MyTable t
WHERE t.[DateColumn] >= @dateVar AND
t.[DateColumn] < @dateEnd;
Toujours à partir de cet article: l'utilisation de BETWEEN
, DATEDIFF
ou CONVERT(CHAR(8)...
est plus lente.
Voici un exemple:
J'ai une table Order avec un champ DateTime appelé OrderDate. Je souhaite récupérer toutes les commandes dont la date de commande est égale au 01/01/2006. il y a de nouvelles façons de le faire:
1) WHERE DateDiff(dd, OrderDate, '01/01/2006') = 0
2) WHERE Convert(varchar(20), OrderDate, 101) = '01/01/2006'
3) WHERE Year(OrderDate) = 2006 AND Month(OrderDate) = 1 and Day(OrderDate)=1
4) WHERE OrderDate LIKE '01/01/2006%'
5) WHERE OrderDate >= '01/01/2006' AND OrderDate < '01/02/2006'
Est trouvé ici
Obtenez des éléments lorsque la date se situe entre la date du et la date.
où convertir (date, fromdate, 103) <= '2016-07-26' et convertir (date, toDate, 103)> = '2016-07-26'
Vous pouvez ajouter une colonne calculée qui inclut uniquement la date sans l'heure. Entre les deux options, j'irais avec l'opérateur BETWEEN
parce qu'il est plus "propre" pour moi et devrait mieux utiliser les index. La comparaison des plans d'exécution semble indiquer que BETWEEN
serait plus rapide; cependant, dans les tests réels, ils ont effectué la même chose.