Alle de eksisterende (fungerende) svar har et af to problemer:
- De vil ignorere indekser i den kolonne, der søges i
- Det vil (potentielt) vælge data, der ikke er tilsigtet, hvilket i det stille ødelægger dine resultater.
1. Ignorerede indekser:
For det meste, når en kolonne, der søges i, har en funktion kaldet på sig (inklusive implicit, som for CAST
), skal optimeringsværktøjet ignorere indekser i kolonnen og søge gennem hver post. Her er et hurtigt eksempel:
Vi har at gøre med tidsstempler, og de fleste RDBMS'er har en tendens til at gemme denne information som en stigende værdi af en eller anden art, normalt en long
eller BIGINTEGER
antal milli-/nanosekunder. Det aktuelle klokkeslæt ser således ud/lagres således:
1402401635000000 -- 2014-06-10 12:00:35.000000 GMT
Du kan ikke se 'År'-værdien ('2014'
) derinde, gør du? Faktisk er der en del kompliceret matematik at oversætte frem og tilbage. Så hvis du kalder nogen af funktionerne til ekstraktion/dato-delen i den søgte kolonne, skal serveren udføre al den matematik for at finde ud af, om du kan inkludere den i resultaterne. På små borde er dette ikke et problem, men efterhånden som procentdelen af udvalgte rækker falder, bliver dette et større og større dræn. Så i dette tilfælde gør du det en anden gang for at spørge om MONTH
... ja, du forstår billedet.
2. Utilsigtede data:
Afhængigt af den særlige version af SQL Server og kolonnedatatyper, ved hjælp af BETWEEN
(eller lignende inklusive øvre grænseområder:<=
) kan resultere i, at de forkerte data bliver valgt. Grundlæggende ender du potentielt med at inkludere data fra midnat den "næste" dag eller ekskludere en del af den "aktuelle" dags registreringer.
Hvad du bør gør:
Så vi har brug for en måde, der er sikker for vores data og vil bruge indekser (hvis det er levedygtigt). Den korrekte måde er så af formen:
WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth
Da der kun er én måned, @startOfPreviousMonth
kan nemt erstattes/afledes af:
DATEADD(month, -1, @startOCurrentfMonth)
Hvis du skal udlede start-of-current-month i serveren, kan du gøre det via følgende:
DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
En hurtig forklaring her. Den initiale DATEDIFF(...)
vil få forskellen mellem begyndelsen af den nuværende æra (0001-01-01
- AD, CE, hvad som helst), hvilket i det væsentlige returnerer et stort heltal. Dette er antallet af måneder til starten af den aktuelle måned. Vi tilføjer derefter dette nummer til starten af æraen, som er i starten af den givne måned.
Så dit fulde script kunne/bør ligne følgende:
DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally misspelled
AND date_created < @startOfCurrentMonth
Alle datooperationer udføres således kun én gang, på én værdi; optimeringsværktøjet er gratis at bruge indekser, og der vil ikke blive inkluderet forkerte data.