Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Quando si usa GETDATE() in molti posti, è meglio usare una variabile?

[NOTA:se hai intenzione di effettuare un downvote di questa risposta, lascia un commento che spieghi il motivo. È già stato sottoposto a downvoted molte volte e alla fine ypercube (grazie) ha spiegato almeno un motivo. Non posso rimuovere la risposta perché è stata accettata, quindi potresti anche contribuire a migliorarla.]

Secondo questo scambio su Microsoft, GETDATE() passato dall'essere costante all'interno di una query a non deterministico in SQL Server 2005. In retrospettiva, non penso che sia accurato. Penso che fosse completamente non deterministico prima di SQL Server 2005 e poi hackerato in qualcosa chiamato "costante di runtime non deterministica" da SQL Server 2005". La frase successiva sembra davvero significare "costante all'interno di una query".

(E GETDATE() è definito come inequivocabilmente e orgogliosamente non deterministico, senza qualificatori.)

Purtroppo, in SQL Server, non deterministico non significa che una funzione viene valutata per ogni riga. SQL Server lo rende davvero inutilmente complicato e ambiguo con pochissima documentazione sull'argomento.

In pratica la chiamata di funzione viene valutata quando la query è in esecuzione anziché una volta quando la query viene compilata e il suo valore cambia ogni volta che viene chiamata. In pratica, GETDATE() viene valutato solo una volta per ogni espressione in cui viene utilizzata, al tempo di esecuzione anziché tempo di compilazione . Tuttavia, Microsoft inserisce rand() e getdate() in una categoria speciale, chiamata funzioni costanti di runtime non deterministiche. Al contrario, Postgres non salta attraverso tali cerchi, chiama semplicemente funzioni che hanno un valore costante quando vengono eseguite come "stabili".

Nonostante il commento di Martin Smith, la documentazione di SQL Server semplicemente non è esplicita su questo argomento -- GETDATE() è descritto come "costante di runtime non deterministico" e "non deterministico", ma quel termine non è realmente spiegato. L'unico posto in cui ho trovato il termine , ad esempio, le righe successive nella documentazione dicono di non utilizzare funzioni non deterministiche nelle sottoquery. Sarebbe un consiglio sciocco per "costante di runtime non deterministica".

Suggerirei di utilizzare una variabile con una costante anche all'interno di una query, in modo da avere un valore coerente. Questo rende anche l'intenzione abbastanza chiara:vuoi un singolo valore all'interno della query. All'interno di una singola query, puoi fare qualcosa come:

select . . . 
from (select getdate() as now) params cross join
     . . . 

In realtà, questo è un suggerimento che dovrebbe valutare solo una volta nella query, ma potrebbero esserci delle eccezioni. Sorge confusione perché getdate() restituisce lo stesso valore su tutte le diverse righe, ma può restituire valori diversi in colonne diverse. Ogni espressione con getdate() viene valutato in modo indipendente. Ciò è ovvio se esegui:

select rand(), rand()
from (values (1), (2), (3)) v(x);

All'interno di una procedura memorizzata, vorresti avere un singolo valore in una variabile. Cosa succede se la stored procedure viene eseguita al passare della mezzanotte e la data cambia? Che impatto ha sui risultati?

Per quanto riguarda le prestazioni, suppongo che la ricerca di data/ora sia minima e per una query si verifica una volta per espressione quando la query inizia a essere eseguita. Questo non dovrebbe essere un problema di prestazioni, ma più un problema di coerenza del codice.