#sql #sql-server #performance
#sql #sql-server #Производительность
Вопрос:
Небольшое замечание: мы используем SQL Server 2012 в доме, но проблема, похоже, также возникает в 2008 и 2008 R2, а также, возможно, в более старых версиях.
Я исследовал проблему с производительностью в каком-то нашем коде, и я отследил проблему до следующего очень простого запроса:
SELECT min(document_id)
FROM document
WHERE document_id IN
(SELECT TOP 5000 document_id FROM document WHERE document_id > 442684)
Я заметил, что для возврата этого запроса требуется абсурдно много времени (от 18 до 70 секунд в зависимости от ресурсов компьютера, на котором он выполняется), когда это конечное значение (после большего, чем) составляет примерно 442000 или больше. Все, что ниже этого, запрос возвращается почти мгновенно.
С тех пор я изменил запрос, чтобы он выглядел следующим образом:
SELECT min(t.document_id)
FROM (SELECT TOP 5000 document_id FROM document WHERE document_id > 442684) t
Это немедленно возвращает все значения>, с которыми я тестировал.
Я решил проблему с производительностью, поэтому я в целом доволен, но я все еще ломаю голову над тем, почему исходный запрос был выполнен так плохо для 442000 и почему он выполняется быстро практически для любого значения ниже этого (400000, 350000 и т. Д.).
Кто-нибудь может это объяснить?
РЕДАКТИРОВАТЬ: исправлено, что 2-й запрос был минимальным, а не максимальным (это была опечатка)
Комментарии:
1. У вас должно быть
ORDER
предложение в подзапросе, без него результат не будет гарантированно одинаковым каждый раз.
Ответ №1:
Секрет понимания производительности SQL Server (и других баз данных) заключается в плане выполнения. Вам нужно будет взглянуть на план выполнения запросов, чтобы понять, что происходит.
В первой версии вашего запроса есть операция объединения. IN
с помощью подзапроса есть еще один способ выразить JOIN
. В SQL Server есть несколько способов реализации объединений, таких как сопоставление хэшей, сортировка слиянием, вложенный цикл и операции поиска по индексу. Оптимизатор выбирает тот, который, по его мнению, является лучшим.
Не видя планов выполнения, я предполагаю, что оптимизатор меняет свое мнение относительно наилучшего алгоритма для использования in
. По моему опыту, это обычно означает, что он переключился на алгоритм вложенного цикла с более разумного.
Комментарии:
1. Спасибо, что вмешались. Я предположил, что это скрытая особенность SQL Server, и у меня было внутреннее чувство, что это связано с предложением IN . Я не чувствую необходимости углубляться в планы выполнения для каждой версии моего запроса выше. Я рад просто знать, что в этом заключается проблема с производительностью. Еще раз спасибо.
2. @user3771607 . . . Мне приходилось иметь дело с системами, в которых такие изменения занимали бы запрос от 2 минут до … ну, не завершались за ночь и убивали ночной пакетный запуск. Возможно, вам захочется узнать о планах запросов и подсказках оптимизатора по мере продвижения вперед с SQL Server.
3. @Gordon_Linoff Спасибо за совет. Я обязательно буду изучать планы запросов и подсказки оптимизатора по мере продвижения вперед в разработке базы данных. Мне потребовалось больше времени, чем следовало, чтобы отследить эту проблему.
Ответ №2:
Измените свой запрос на
выберите min(document_id) из документа, где document_id> 442684
Выбор в (выберите top 5000) — плохая идея в sql — он может расшириться до 5000, если тесты. Не знаю, почему оптимизатор хорошо работал в случае max ()
Комментарии:
1. Спасибо, это определенно более разумный подход для поиска минимального идентификатора документа, большего, чем x. Я это реализую. Мы также (в отдельном запросе) находим максимальный идентификатор документа в следующих 5000 документах, идентификатор которых больше указанного числа, поэтому я полагаю, что мне придется сохранить «top 5000» в этом запросе.
2. Вы уверены, что это то, что он делает? Поскольку у вас нет порядка, это могут быть любые 5000 строк.