Мне просто любопытно, почему агрегатный запрос выполняется с GROUP BY
предложением гораздо быстрее , чем без него.
Например, этот запрос выполняется почти 10 секунд
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
В то время как этот занимает меньше секунды
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
В CreatedDate
этом случае есть только один , поэтому сгруппированный запрос возвращает те же результаты, что и разгруппированный.
Я заметил, что планы выполнения для этих двух запросов различны - во втором запросе используется параллелизм, а в первом - нет.
Является ли нормальным для SQL-сервера оценивать агрегатный запрос по-другому, если у него нет предложения GROUP BY? И есть ли что-то, что я могу сделать, чтобы улучшить производительность 1-го запроса без использования GROUP BY
предложения?
редактировать
Я только что узнал, что могу использовать OPTION(querytraceon 8649)
для установки издержек параллелизма на 0, что заставляет запрос использовать некоторый параллелизм и сокращает время выполнения до 2 секунд, хотя я не знаю, есть ли какие-либо недостатки в использовании этой подсказки запроса.
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)
Я бы все же предпочел более короткое время выполнения, поскольку запрос предназначен для заполнения значения при выборе пользователя, поэтому в идеале он должен быть мгновенным, как сгруппированный запрос. Прямо сейчас я просто завершаю свой запрос, но я знаю, что это не идеальное решение.
SELECT Min(CreatedDate)
FROM
(
SELECT Min(CreatedDate) as CreatedDate
FROM MyTable WITH (NOLOCK)
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
) as T
Редактировать № 2
В ответ на запрос Мартина о дополнительной информации :
Оба CreatedDate
и SomeIndexedValue
имеют отдельный неуникальный некластеризованный индекс. SomeIndexedValue
на самом деле это поле varchar (7), хотя оно хранит числовое значение, указывающее на PK (int) другой таблицы. Связь между двумя таблицами не определена в базе данных. Я не должен изменять базу данных вообще, и могу только писать запросы, которые запрашивают данные.
MyTable
содержит более 3 миллионов записей, и каждой записи присваивается группа, к которой она принадлежит ( SomeIndexedValue
). В группах может быть от 1 до 200 000 записей
MAXDOP
устанавливает максимальную степень параллелизма, которая ограничивает число процессоров, которые может использовать запрос. Это в основном заставит второй запрос работать так же медленно, как и первый, поскольку он удаляет возможности использовать параллелизм, а это не то, что мне нужно.По моему мнению, причина проблемы в том, что оптимизатор сервера sql не ищет план BEST, а ищет хороший план, о чем свидетельствует тот факт, что после форсирования параллелизма запрос выполнялся намного быстрее, что было у оптимизатора. не сделано само по себе.
Я также видел много ситуаций, когда переписывание запроса в другом формате было различием между распараллеливанием (например, хотя большинство статей по SQL рекомендуют параметризацию, я обнаружил, что это иногда вызывает параллелизацию noy, даже когда вынюхиваемые параметры были такими же, как и у других). - распараллеливание одного или объединение двух запросов с помощью UNION ALL иногда может исключить распараллеливание).
Таким образом, правильное решение может заключаться в том, чтобы попробовать разные способы написания запроса, такие как временные таблицы, переменные таблиц, cte, производные таблицы, параметризация и т. Д., А также играть с индексами, индексированными представлениями или отфильтрованными индексами в Чтобы получить лучший план.
источник