#sql #sql-server #tsql
#sql #sql-сервер #tsql
Вопрос:
Кто-то, с кем я работал, написал то, что я сначала считал очень избыточным запросом. Я рассматривал возможность удаления избыточности, но потом мне пришло в голову, что на самом деле это может быть менее эффективно, если я это сделаю.
Обычно для необязательных аргументов фильтра я бы написал что-то вроде этого:
SELECT stuff
FROM data
WHERE (@arg1 IS NULL OR Field1 = @arg1)
AND (@arg2 IS NULL OR Field2 = @arg2)
...
То, как он написал свой запрос, было больше похоже на это:
IF @arg1 IS NOT NULL AND @arg2 IS NOT NULL
BEGIN
SELECT stuff
FROM data
WHERE Field1 = @arg1
AND Field2 = @arg2
END
IF @arg1 IS NULL AND @arg2 IS NOT NULL
BEGIN
SELECT stuff
FROM data
WHERE Field2 = @arg2
END
IF @arg1 IS NOT NULL AND @arg2 IS NULL
BEGIN
SELECT stuff
FROM data
WHERE Field1 = @arg1
END
С одной стороны, избыточность кажется ужасной (особенно когда в реальной вещи было 12 блоков, 5 аргументов, 8 полей и 2 таблицы с объединением). Но, с другой стороны … это вытягивает много сравнений из итерации. В фильтре выполняются только те сравнения, которые необходимо выполнить, а повторяющееся ненужное сравнение с NULL удаляется в одно место за пределами фактического запроса. (В основном «постоянная» или «фиксированная» информация извлекается из «цикла» запроса.)
Итак … действительно ли вторая версия здесь «лучше» с точки зрения производительности? Я знаю, преждевременная оптимизация и все такое, и читаемость важнее, и DRY и т. Д., Но все же мне интересно, является ли это более эффективным с точки зрения производительности? (Я бы хотел надеяться, что они в основном эквивалентны, и что механизм БД уже должен делать что-то подобное.)
Комментарии:
1. Единственный способ точно узнать, работает ли он лучше, — это запустить набор тестов и сравнить планы выполнения. Однако существует очень высокая вероятность того, что только использование интересующих условий будет работать лучше, потому что SQL Server часто плохо работает с
OR
условиями, особенно с большим количествомOR
условий. Но я повторяю, единственный способ узнать наверняка — это проверить это. Эта проблема часто решается с помощью динамического SQL, чтобы избежать повторения кода, о котором вы упомянули. Это действительно создает проблемы, связанные с динамическим SQL, но в этой ситуации их часто считают одним из двух зол.2. Да, ваш «избыточный» запрос, вероятно, начал свою жизнь так, как вы могли бы ожидать, и закончил так, как есть, чтобы повысить производительность. Когда это одна или две переменные @, которые являются частью критериев or , я сделал именно это, когда это больше, чем на самом деле динамическое построение запроса более управляемо, имхо. Вы можете создать надуманный пример для тестирования, но я бы поспорил, что критерий or «@variable» is null приведет к сканированию индекса или таблицы, и если вы удалите условие or , вы получите оптимальный поиск по индексу, предполагая, конечно, что подходящий индекс существует.
3. Это будет иметь точно такую же проблему.
4. Как правило, SQL Server будет выполнять постоянную оценку перед выполнением запроса, т.Е. Все случаи
@argX IS NULL
будут оцениваться сначала перед выполнением запроса. Проблема может возникнуть там, где при первом выполнении создается план запроса. Этот план может в конечном итоге хорошо подойти для одного сценария, но оказаться плохим планом для других.5. Вы сделали предположение и попали в ловушку, приравняв «очень избыточный запрос» к неоптимальному или неэффективному или «нуждается в исправлении». Так что перестань это делать. Никогда не исправляйте то, что работает, независимо от того, насколько сильно код нарушает ваши чувства. Я предлагаю вам прочитать обсуждение динамических условий поиска Эрланда и обсуждение кухонной раковины Аарона