Ответ 1
[ПРИМЕЧАНИЕ. Если вы хотите уменьшить этот ответ, пожалуйста, оставьте комментарий, объясняющий, почему. Он уже многократно опущен, и, наконец, ypercube (спасибо) объяснил хотя бы одну причину. Я не могу удалить ответ, потому что он принят, поэтому вы можете также помочь его улучшить.]
Согласно этому обмену на Microsoft, GETDATE()
переключился с константы в запросе на недетерминированный в SQL Server 2005. Оглядываясь назад, я не думаю, что это точно. Я думаю, что он был полностью недетерминирован до SQL Server 2005, а затем взломан во что-то, называемое "неопределенная константа выполнения" с SQL Server 2005. Более поздняя фраза действительно означает "константа в запросе".
(И GETDATE()
определяется как однозначно и с гордостью недетерминированный, без квалификаторов.)
Увы, в SQL Server не детерминированность не означает, что функция оценивается для каждой строки. SQL Server действительно делает это излишне сложным и двусмысленным с очень небольшим количеством документации по этому вопросу.
На практике вызов функции оценивается, когда запрос выполняется не один раз, когда запрос компилируется, и его значение изменяется каждый раз, когда он вызывается. На практике GETDATE()
оценивается только один раз для каждого выражения, где оно используется, - во время выполнения, а не времени компиляции. Тем не менее, Microsoft помещает rand()
и getdate()
в специальную категорию, называемую getdate()
постоянными функциями времени исполнения. Напротив, Postgres не перескакивает через такие обручи, он просто вызывает функции, которые имеют постоянное значение при выполнении как "стабильный".
Несмотря на комментарий Мартина Смита, документация SQL Server просто не является явной в этом вопросе - GETDATE()
описывается как "недетерминированная" и " GETDATE()
константа времени выполнения", но этот термин на самом деле не объясняется. В одном месте, где я нашел этот термин, например, следующие строки в документации говорят о том, что нельзя использовать недетерминированные функции в подзапросах. Это было бы глупым советом для "недетерминированной постоянной времени выполнения".
Я бы предложил использовать переменную с константой даже внутри запроса, поэтому у вас есть постоянное значение. Это также делает намерение совершенно ясным: вы хотите получить одно значение внутри запроса. В одном запросе вы можете сделать что-то вроде:
select . . .
from (select getdate() as now) params cross join
. . .
На самом деле это предложение, которое должно оценивать только один раз в запросе, но могут быть исключения. Путаница возникает из-за getdate()
что getdate()
возвращает одно и то же значение во всех разных строках, но может возвращать разные значения в разных столбцах. Каждое выражение с getdate()
оценивается независимо. Это очевидно, если вы запустите:
select rand(), rand()
from (values (1), (2), (3)) v(x);
В хранимой процедуре вы хотели бы иметь одно значение в переменной. Что произойдет, если хранимая процедура запускается с пропуском в полночь, а дата меняется? Какое влияние это оказывает на результаты?
Что касается производительности, то я предполагаю, что поиск по дате/времени минимален, и запрос возникает один раз для каждого выражения при запуске запроса. На самом деле это не проблема производительности, а скорее проблема согласованности кода.