Conversia câmpurile datetime SQL server pentru a compara numai piese de data, cu lookups indexate

voturi
28

Am făcut - o convert(varchar,datefield,112)pe fiecare domeniu data la care eu sunt , folosind în „între“ interogări în SQL server pentru a se asigura că eu sunt doar pentru datele contabile și nu lipsesc nici în funcție de partea de timp a câmpurilor datetime.

Acum, am auzit că cei convertiți nu sunt indexabil și că există metode mai bune, în SQL Server 2005, pentru a compara partea data datetimes într-o interogare pentru a determina dacă datele se încadrează într-un interval.

Care este optimă, indexabil, metoda de a face ceva de genul:

select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'
Întrebat 09/12/2008 la 15:59
sursa de către utilizator
În alte limbi...                            


5 răspunsuri

voturi
65

Cel mai bun mod de a stripa porțiunea de timp a unui câmp datetime utilizează datediff și funcțiile dateadd.

   DateAdd(day, datediff(day,0, MydateValue), 0)

Acest lucru ia advantedge de faptul că stochează SQL Server data ca două numere întregi, una reprezentând numărul de zile de la ziua „0“ - (1 ianuarie 1900), iar al doilea , care reprezintă numărul de căpușe (fiecare de căpușă este de aproximativ 3.33 ms ) începând cu miezul nopții (pentru moment) *.

formula de mai sus, pur și simplu trebuie să citească doar primul număr întreg. Nu există nici o conversie sau procesare necesară, de aceea este extrem de rapid.

Pentru a face interogări utilizează un index ... utilizați această formulă pe intrarea de filtrare parametrii în primul rând, sau pe „cealaltă“ parte a semnului egal din câmpul de timp dată tabele, astfel încât Optimizatorul de interogare nu trebuie să ruleze calcul pe fiecare domeniu datetime din tabel pentru a determina rândurile care satisfac predicatul filtrului. Acest lucru face ca argument cautarea „SARG-capabil“ (Căutare ARGUMENT)

Where MyDateTimeColumn > DateAdd(day, 
      datediff(day,0, @MydateParameter), 0)    -- SARG-able

Decat

Where DateAdd(day, datediff(day,0, 
      MyDateTimeColumn ), 0) > @MydateParameter -- Not SARG-able

* NOTĂ. Pe plan intern, al doilea număr întreg (partea de timp) stochează căpușe. Într-o zi, există 24 x 60 X 60 X 300 = 25,920,000 căpușe (serendipitously chiar sub valoarea maximă un întreg pe 32 de biți poate deține). Cu toate acestea, nu aveți nevoie să vă faceți griji cu privire la acest lucru atunci când modificarea aritmetic un datetime ... Atunci când adăugarea sau scăderea valorilor din datetimes pot trata valoarea ca o fracțiune de parcă ar fi fost exact egală cu porțiunea fracționată a unei zile, ca și cum valoarea totală datetime a fost un număr în virgulă mobilă constând dintr-o porțiune întreg reprezentând data și porțiunea fracționară reprezentând timpul). și anume,

`Declare @Dt DateTime  Set @Dt = getdate()  
 Set @Dt = @Dt + 1.0/24  -- Adds one hour  
 Select @Dt  
 Set @Dt = @Dt - .25 -- Moves back 6 hours  
 Select @Dt`
Publicat 09/12/2008 la 16:07
sursa de către utilizator

voturi
5

Conversia tipurilor numerice la valori string (un tip de box) nu este cea mai bună metodă de a face performante ceea ce căutați. Ei nu chiar despre indicele capabil, pentru că tipul actual coloană este timpul dată.

Dacă sunteți în căutarea pentru cel mai bun mod de interogare pentru datele, apoi exemplul dvs. este corect, dar poate doriți să ia în considerare diferența de 3 ms precizie în MSSQL. Aceasta poate însemna că înregistrările de la o zi pot să apară în urma o altă zi.

Acest

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

Ar trebui să fie acest lucru

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'
Publicat 09/12/2008 la 16:11
sursa de către utilizator

voturi
2

Este corect - a face conversia se va executa conversia pentru fiecare rând interogate. Este mai bine să părăsească coloanele data ca datele, și să treacă în contul dvs. în cazul în care clauzele date:

select * from appointments where appointmentdate between 
'08/01/2008' AND '08/16/2008'

Notă: Lăsând în afara timpului înseamnă miezul nopții (00: 00.000), așa că va cuprinde tot timpul pentru 08/01, și în orice moment de la 08/15, și tot ceea ce este exact 08/16/2008 00:00:00

Publicat 09/12/2008 la 16:06
sursa de către utilizator

voturi
1

Au calculat o coloană calculează expresia persistau aveți nevoie. În cazul în care coloanele sunt calculate și a persistat, ele pot fi, de asemenea, indexate.

Publicat 09/12/2008 la 16:10
sursa de către utilizator

voturi
0

Există , de asemenea , modul în care este descris la http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/

SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)
Publicat 28/09/2011 la 13:31
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more