Может ли кто-нибудь объяснить разницу между двумя запросами? - PullRequest
2 голосов
/ 28 марта 2012

Первый запрос:

declare @myDate datetime = DATEADD(D,-2000,getdate())
SELECT * FROM [myTable]  
where CreatedDate >= @myDate

Второй запрос:

SELECT * FROM [myTable]  
where CreatedDate >= DATEADD(D,-2000,getdate())

Я ожидаю, что первый запрос может быть быстрее, потому что функция dateadd вычисляется один раз. Но на практике эти запросы равны (2 секунды, 30 000 строк)

Ответы [ 3 ]

3 голосов
/ 28 марта 2012

getdate() - это постоянная функция времени выполнения , которая оценивается только один раз для каждой ссылки на функцию, поэтому

SELECT GETDATE()
FROM SomeBigTable

будет возвращать один и тот же результат для всех строк независимо от того, как долгозапрос выполняется для выполнения.

Однако есть разница между ними.Поскольку первый использует переменную, и план компилируется до того, как переменная будет присвоена SQL Server (при отсутствии перекомпиляции) будет предполагать, что будет возвращено 30% строк.Это предположение может привести к тому, что он будет использовать план, отличный от второго запроса.

При использовании GETDATE() непосредственно в фильтре следует учитывать, что он оценивает GETDATE() во время компиляции и после этого возможнодля резкого изменения избирательности без запроса или изменения данных для запуска перекомпиляции.В приведенном ниже примере для таблицы из 1000 строк запрос с использованием переменной приводит к плану с предполагаемыми 300 строками и полному сканированию таблицы, тогда как запрос с вызовом функции внедряет оценку в 1 строку и выполняет поиск по закладкам.Это точно при первом запуске, но при втором запуске из-за времени теперь все строки соответствуют требованиям, и в итоге выполняется 1000 таких случайных поисков.

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]
1 голос
/ 28 марта 2012

SQL не собирается пересчитывать DATEADD для каждой строки.В любом случае он будет рассчитан один раз, а затем проведет сравнение с результатом по всем строкам таблицы.Два разных способа, один (возможно, излишне) более многословный, чем другой, но в итоге они дают один и тот же результат.

0 голосов
/ 28 марта 2012

Оптимизатор SQL-сервера помогает сделать последний запрос более оптимальным.

Взгляните на план запроса .

...