问题
The first query is:
declare @myDate datetime = DATEADD(D,-2000,getdate())
SELECT * FROM [myTable]
where CreatedDate >= @myDate
The second query is:
SELECT * FROM [myTable]
where CreatedDate >= DATEADD(D,-2000,getdate())
I expect that the first query may be faster, because of 'dateadd' function calculates once. But in practice this queries are both equal (2 seconds, 30 000 rows)
回答1:
getdate()
is a runtime constant function and is only evaluated once per function reference which is why
SELECT GETDATE()
FROM SomeBigTable
will return the same result for all rows regardless of how long the query takes to run.
There is a difference between the two however. As the first one uses a variable and the plan is compiled before the variable is assigned to SQL Server will (in the absence of a recompile) assume that 30% of the rows will be returned. This guess may cause it to use a different plan than the second query.
Something to bear in mind with using GETDATE()
directly in a filter is that it evaluates GETDATE()
at compile time and thereafter it is possible for the selectivity to change dramatically without either the query or the data changing to trigger a recompile. In the example below against a 1,000 row table the query using a variable leads to a plan with an estimated 300 rows and a full table scan whereas the query with the function call embedded estimates 1 row and does a bookmark lookup. This is accurate on the first run but on the second run due to the passage of time now all rows qualify and it ends up doing 1,000 such random lookups.
USE tempdb;
CREATE TABLE [myTable]
(
CreatedDate datetime,
Filler char(8000) NULL
)
CREATE NONCLUSTERED INDEX ix ON [myTable](CreatedDate)
INSERT INTO [myTable](CreatedDate)
/*Insert 1 row that initially qualifies*/
SELECT DATEADD(D,-2001,getdate())
UNION ALL
/*And 999 rows that don't initially qualify*/
SELECT TOP 999 DATEADD(minute,1, DATEADD(D,-2000,getdate()))
FROM master..spt_values
EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT *
FROM [myTable]
WHERE CreatedDate <= @myDate
')
EXEC('
SELECT *
FROM [myTable]
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')
RAISERROR ('Delay',0,1) WITH NOWAIT
WAITFOR DELAY '00:01:01'
EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT *
FROM [myTable]
WHERE CreatedDate <= @myDate
')
EXEC('
SELECT *
FROM [myTable]
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')
DROP TABLE [myTable]
回答2:
SQL isn't going to recalculate DATEADD for every single row. Either way it's going to calculate it once and then run a comparison to the result across your rows of your table. Two different ways, one (perhaps unnecessarily) more verbose than the other, but in the end they give the same result.
回答3:
The SQL server optimizer is assisting with making the latter query more optimal.
Have a look at the query plan.
来源:https://stackoverflow.com/questions/9905677/could-somebody-explaine-difference-between-two-queries