Производительность простых SQL-запросов меня озадачивает

#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 строк.