2013-03-11 43 views
21

Ho un campo SQL datetime in una tabella molto grande. È indicizzato e deve essere interrogato.Qual è il modo ottimale per confrontare le date nel server Microsoft SQL?

Il problema è che SQL memorizza sempre il componente orario (anche se è sempre mezzanotte), ma le ricerche sono relative al giorno anziché al tempo.

declare @dateVar datetime = '2013-03-11; 

select t.[DateColumn] 
from MyTable t 
where t.[DateColumn] = dateVar; 

non tornerà nulla, come il t.[DateColumn] include sempre una componente di tempo.

La mia domanda è qual è il modo migliore intorno a questo?

Sembra che ci siano due gruppi principali di opzioni:

  1. Creare una seconda variabile utilizzando dateadd e utilizzare un between ... and o >= ... and ... <=.

  2. Convertire il t.[DateColumn] in un componente solo per la data. Penso che questo causerà l'ignoranza di qualsiasi indice.

Entrambe sembrano molto disordinate: non voglio davvero fare un confronto tra intervalli o scansionare il tavolo.

C'è un modo migliore?

Se una di queste opzioni è sempre in modo ottimale, come e perché?

risposta

24

La conversione in un DATE o in un intervallo di date aperto in ogni caso produrrà la migliore prestazione. Cordiali saluti, convertire fino ad oggi utilizzando un indice sono i migliori interpreti. Più la prova di un diverse tecniche nell'articolo: What is the most efficient way to trim time from datetime? Scritto da Aaron Bertrand

Da tale articolo:

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; 

Anche da tale articolo: Usando BETWEEN, DATEDIFF o CONVERT(CHAR(8)... sono tutti più lenti.

+2

@Keith Grazie per aver specificato esempi .. e buona domanda;) –

10

Ecco un esempio:

Ho una tabella Ordine con un campo datetime chiamato DataOrdine. Voglio recuperare tutti gli ordini in cui la data dell'ordine è uguale a 01/01/2006. ci sono prossimi modi per farlo:

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' 

si trova here

+0

di tutti coloro, # 1 è considerato il più efficiente: http://www.sqlservercentral.com/Forums/Topic937765-338-1.aspx – RandomUs1r

+1

@ L'opzione RandomUs1r # 1 deve eseguire il calcolo 'datediff' per ogni riga della tabella, sicuramente ha vinto essere il più veloce o il più efficiente Lo stesso per l'opzione # 2 con la conversione 'varchar (20)'. Le opzioni # 4 e # 5 sono più promettenti, e aggiungerei altre due: 6) 'dove OrderDate tra @dateVar e dateadd (day, 1, @dateVar)' e 7) 'WHERE convert (date, OrderDate) = @ dateVar' – Keith

+3

Di questi 5 metodi suggeriti 1-4 sono tutti molto lenti. 5 è veloce per le tabelle ammucchiate e il metodo più veloce ('convert (date, OrderDate)' vede la risposta selezionata) non è nemmeno nella lista. – Keith

0

si potrebbe aggiungere una colonna calcolata che include solo la data senza il tempo. Tra le due opzioni, andrei con l'operatore BETWEEN perché è "più pulito" per me e dovrebbe fare un uso migliore degli indici. Confrontando i piani di esecuzione sembrerebbe indicare che BETWEEN sarebbe più veloce; tuttavia, nei test effettivi hanno eseguito lo stesso.

+1

Si scopre che ['between' è una cattiva idea qui] (http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do-between-and-the-devil-have- in-common.aspx). – Keith

+1

@Keith +1 Grazie per il collegamento. Ero a conoscenza della maggior parte dei problemi (sapevo che era inclusivo e aggiungo abitualmente un valore temporale alla data di fine quando necessario), ma gli ultimi erano nuovi per me. Al lavoro tutti i valori temporali che selezioniamo vengono troncati al minuto o al secondo (no, non è stata la mia decisione, sì, la mancanza di precisione è fastidiosa.) Quindi i problemi nano-secondari non sono ancora usciti , ma sono potenzialmente abbastanza seri probabilmente farò cambiare l'uso di 'BETWEEN' a' => ... <'per discutere con gli altri sviluppatori oggi. –

0

Ottieni articoli quando la data è compresa tra data e ora.

dove convertito (data, fromdate, 103) < = '2016/07/26' e convertire (data, todate, 103)> = '2016/07/26'

+2

Ciao @gaze, benvenuto su Stack Overflow. La tua risposta in realtà non aggiunge nulla qui - se leggi la risposta accettata vedrai che hanno già trattato 'convert' e spiegato se cambiare il tipo o l'utilizzo è meglio basato su indici, che è proprio quello che stavo chiedendo per. Per alzarti, vota che hai davvero bisogno di aggiungere qualcosa che gli altri non hanno o rispondi prima. – Keith

Problemi correlati