J'ai besoin d'écrire une requête qui regroupera un grand nombre d'enregistrements par périodes de temps de l'année à l'heure.
Mon approche initiale a consisté à décider des périodes de manière procédurale en C #, à parcourir chacune d'elles et à exécuter le SQL pour obtenir les données pour cette période, en créant l'ensemble de données au fur et à mesure.
SELECT Sum(someValues)
FROM table1
WHERE deliveryDate BETWEEN @fromDate AND @ toDate
J'ai découvert par la suite que je pouvais grouper les enregistrements en utilisant l'année (), le mois () le jour () et la partie de date (semaine, date) et la partie de date (hh, date).
SELECT Sum(someValues)
FROM table1
GROUP BY Year(deliveryDate), Month(deliveryDate), Day(deliveryDate)
Ma préoccupation est que l'utilisation de datepart dans un groupe par entraînera de moins bonnes performances que l'exécution de la requête plusieurs fois pendant une période définie en raison de l'impossibilité d'utiliser l'index sur le champ datetime aussi efficacement; des pensées quant à savoir si cela est vrai?
Merci.
Comme pour tout ce qui concerne les performances Mesurer
La vérification du plan de requête pour la deuxième approche vous indiquera à l'avance tout problème évident (une analyse complète de la table lorsque vous savez que celle-ci n'est pas nécessaire), mais il n'y a pas de substitut à la mesure. Dans les tests de performances SQL, cette mesure doit être effectuée avec des tailles de données de test appropriées.
Étant donné qu'il s'agit d'un cas complexe, vous ne comparez pas simplement deux façons différentes de faire une seule requête, mais comparez une approche de requête unique à une approche itérative, des aspects de votre environnement peuvent jouer un rôle majeur dans les performances réelles.
Plus précisément
Si vous mettez une formule dans la partie champ d'une comparaison, vous obtenez un scan de table.
L'index est sur champ, pas sur datepart (champ), donc TOUS les champs doivent être calculés - donc je pense que votre intuition est juste.
Si vous pouvez tolérer l'atteinte des performances de rejoindre une autre table, j'ai une suggestion qui semble étrange mais qui fonctionne vraiment bien.
Créez un tableau que j'appellerai ALMANAC avec des colonnes comme jour de semaine, mois, année. Vous pouvez même ajouter des colonnes pour les fonctionnalités spécifiques à une entreprise d'une date, comme si la date est un jour férié ou non. Vous souhaiterez peut-être ajouter un horodatage de début et de fin, comme indiqué ci-dessous.
Bien que vous puissiez vous en tirer avec une rangée par jour, quand j'ai fait cela, j'ai trouvé pratique d'aller avec une rangée par équipe, où il y a trois équipes par jour. Même à ce rythme, une période de dix ans n'était que d'un peu plus de 10 000 lignes.
Lorsque vous écrivez le SQL pour remplir ce tableau, vous pouvez utiliser toutes les fonctions intégrées orientées par date pour faciliter le travail. Lorsque vous allez faire des requêtes, vous pouvez utiliser la colonne de date comme condition de jointure, ou vous pouvez avoir besoin de deux horodatages pour fournir une plage pour intercepter les horodatages dans la plage. Le reste est aussi simple que de travailler avec tout autre type de données.
vous pouvez faire quelque chose de similaire à ceci:
SELECT Sum(someValues)
FROM
(
SELECT *, Year(deliveryDate) as Y, Month(deliveryDate) as M, Day(deliveryDate) as D
FROM table1
WHERE deliveryDate BETWEEN @fromDate AND @ toDate
) t
GROUP BY Y, M, D
Je cherchais une solution similaire à des fins de création de rapports et je suis tombé sur cet article intitulé Grouper par mois (et autres périodes) . Il montre différentes façons, bonnes et mauvaises, de regrouper par le champ datetime. Vaut vraiment le coup d'oeil.
Je pense que vous devriez le comparer pour obtenir des résultats fiables, mais, à mon humble avis et ma première pensée serait que laisser la DB s'en occuper (votre deuxième approche) serait beaucoup plus rapide que lorsque vous le faites dans votre code client. Avec votre première approche, vous avez plusieurs allers-retours vers la DB, qui je pense seront beaucoup plus chers. :)
Vous voudrez peut-être regarder une approche dimensionnelle (c'est similaire à ce que Walter Mitty a suggéré), où chaque ligne a une clé étrangère pour une dimension de date et/ou d'heure. Cela permet des sommations très flexibles via la jointure à cette table où ces parties sont précalculées. Dans ces cas, la clé est généralement une clé entière naturelle de la forme AAAAMMJJ et HHMMSS qui est relativement performante et également lisible par l'homme.
Une autre alternative pourrait être des vues indexées, où il existe des expressions distinctes pour chacune des parties de date.
Ou des colonnes calculées.
Mais les performances doivent être testées et les plans d'exécution examinés ...