[BEMÆRK:Hvis du vil nedstemme dette svar, bedes du efterlade en kommentar, der forklarer hvorfor. Det er allerede blevet nedstemt mange gange, og endelig forklarede ypercube (tak) mindst én grund til hvorfor. Jeg kan ikke fjerne svaret, fordi det er accepteret, så du kan lige så godt hjælpe med at forbedre det.]
Ifølge denne udveksling på Microsoft, GETDATE()
skiftet fra at være konstant i en forespørgsel til ikke-deterministisk i SQL Server 2005. Set i bakspejlet tror jeg ikke, at det er korrekt. Jeg tror, det var fuldstændig ikke-deterministisk før SQL Server 2005 og derefter hacket ind i noget, der hedder "ikke-deterministisk runtime constant" siden SQL Server 2005". Den senere sætning ser virkelig ud til at betyde "konstant i en forespørgsel".
(Og GETDATE()
er defineret som utvetydigt og stolt ikke-deterministisk, uden kvalificerende.)
Desværre, i SQL Server betyder ikke-deterministisk ikke, at en funktion evalueres for hver række. SQL Server gør virkelig dette unødvendigt kompliceret og tvetydigt med meget lidt dokumentation om emnet.
I praksis evalueres funktionskaldet, når forespørgslen kører i stedet for én gang, når forespørgslen kompileres, og dens værdi ændres, hver gang den kaldes. I praksis GETDATE()
evalueres kun én gang for hvert udtryk, hvor det bruges -- ved udførelsestidspunktet i stedet for kompileringstid . Microsoft sætter dog rand()
og getdate()
ind i en særlig kategori, kaldet ikke-deterministiske køretidskonstantfunktioner. Derimod springer Postgres ikke gennem sådanne bøjler, den kalder bare funktioner, der har en konstant værdi, når de udføres som "stabile".
På trods af Martin Smiths kommentar er SQL Server-dokumentation simpelthen ikke eksplicit i denne sag -- GETDATE()
beskrives som både "ikke-deterministisk" og "ikke-deterministisk køretidskonstant", men det udtryk er ikke rigtig forklaret. Det ene sted, hvor jeg har fundet udtrykket, siger de allernæste linjer i dokumentationen, at man ikke må bruge ikke-deterministiske funktioner i underforespørgsler. Det ville være et dumt råd til "ikke-deterministisk køretidskonstant".
Jeg vil foreslå at bruge en variabel med en konstant selv inden for en forespørgsel, så du har en konsistent værdi. Dette gør også hensigten helt klar:Du vil have en enkelt værdi inde i forespørgslen. Inden for en enkelt forespørgsel kan du gøre noget som:
select . . .
from (select getdate() as now) params cross join
. . .
Faktisk er dette et forslag, som bør evaluere kun én gang i forespørgslen, men der kan være undtagelser. Forvirring opstår fordi getdate()
returnerer den samme værdi på alle forskellige rækker -- men den kan returnere forskellige værdier i forskellige kolonner. Hvert udtryk med getdate()
evalueres uafhængigt. Dette er indlysende, hvis du kører:
select rand(), rand()
from (values (1), (2), (3)) v(x);
Inden for en lagret procedure vil du gerne have en enkelt værdi i en variabel. Hvad sker der, hvis den lagrede procedure køres, når midnat passerer, og datoen ændres? Hvilken indflydelse har det på resultaterne?
Hvad angår ydeevne, er mit gæt, at dato/klokkeslæt-opslaget er minimalt, og at en forespørgsel forekommer én gang pr. udtryk, når forespørgslen begynder at køre. Dette burde egentlig ikke være et præstationsproblem, men mere et problem med kodekonsistens.