Огромная разница в выполнении запросов с использованием идентичного плана - PullRequest
0 голосов
/ 09 января 2020

Я не администратор баз данных, поэтому я постараюсь объяснить это как можно лучше. Мы пытаемся выяснить, почему некоторые запросы выполняются очень быстро, а другие - нет. Сам запрос не меняется, а детали плана не различаются между двумя приведенными ниже идентификаторами планов, вплоть до% затрат на каждом узле. В прошлом мы пытались форсировать лучший план, но из-за обновлений Stats и такой «схемы» он думает, что он изменился, и часто выбрасывает ранее действовавший форсированный план, хотя мы все еще исследуем, решает ли проблема форсирование этих планов. в краткосрочной перспективе или нет.

Кажется странным, это похоже на SQL Сервер переключается между двумя планами случайным образом в течение дня, когда вы думаете, что он перестанет использовать более длительный, даже если хотя мы не можем понять, что на самом деле отличается от двух планов, кроме времени выполнения.

Ссылка на План запроса , сравнение WinMerge XML между двумя планами XML показывает, что они действительно идентичны.

Мы используем SQL Server 2017 RTM CU14, более подробную информацию о версии или конфигурации можно предоставить по запросу или по необходимости.

Query Store Plan

1 Ответ

0 голосов
/ 10 января 2020

Это не ответ «per se», это скорее расширенный комментарий.

План не «сложный», он довольно простой и, кажется, лучший, который вы можете получить (исключая курсор). Две кластеризованные таблицы, seeked и merge join, агрегированные для sum () и помещенные в кластеризованную таблицу в базе данных tempdb для прохождения курсором. Две основные точки (с точки зрения производительности) выглядят следующим образом:

  1. очевидная вставка кластеризованного индекса (запись строк по 1,3 млн.)
  2. оператор сортировки перед агрегатом потока. это, скорее всего, разлив в базу данных tempdb для сортировки (1,3 млн строк). Вы можете убедиться в этом, проверив фактический план выполнения.

"Не очень прямое" наблюдение - это число строк: 1,3 мил перед агрегацией и 1,3 мил после агрегации. Предполагается, что агрегация на самом деле не является агрегацией для вычисления сумм (sum () бессмысленна {?}), А скорее похожа на «отдельный тип» агрегации (использование суммы, потому что столбцы inventsum имеют цифры c). Даже отдельная агрегация здесь может не понадобиться, и вы можете проверить это, проверив, действительно ли значения ITEMID (таблицы INVENTSUM) являются уникальными. Если значения не являются уникальными, то проверьте, является ли ITEMID уникальным для AREAID и INVENTDIMID (то есть элемент может появляться только один раз для области & изобретать {ory}). Если любое из них истинно, то для указанного c запроса ITEMID можно считать уникальным, и в результате агрегирование (GROUP BY cols ...) вообще не требуется.

Теоретически, если ITEMID были «уникальными», и целью был микрооптимизация указанного запроса c, тогда «лучшее» выполнение могло быть достигнуто путем кластеризации INVENTSUM по AREAID, INVENTDIMID, ITEMID

[create unique clustered index inventsumclidx on INVENTSUM(AREAID,INVENTDIMID, ITEMID)] 

и выбора группы по ITEMID, INVENTDIMID

GROUP BY A.ITEMID, A.INVENTDIMID, B.CONFIGID, B.INVENTSIZEID ....
ORDER BY A.ITEMID, A.INVENTDIMID, B.CONFIGID,..

это исключило бы оператор сортировки перед объединением (вся информация уже отсортирована по INVENTDIMID) и оператор агрегирования (вся информация уникальна). Без разлива в tempdb для сортировки перед SEGMENT возможно сокращение времени выполнения на 50%.

если у вас есть доступный тестовый экземпляр, вы можете попробовать его и проверить, есть ли разница:

--drop existing clustered index 
--drop index [I_174ITEMDIMIDX] on dbo.[INVENTSUM]
create unique clustered index inventsumclidx on INVENTSUM(AREAID,INVENTDIMID, ITEMID);
go
--adjust these values
declare @P1 int = 20, @P2 int = 50, @P3 int = 15, @P4 int = 500;

declare cur cursor FAST_FORWARD for 

SELECT 
SUM(A.POSTEDQTY),SUM(A.POSTEDVALUE),SUM(A.PHYSICALVALUE),SUM(A.DEDUCTED),SUM(A.REGISTERED),SUM(A.RECEIVED),SUM(A.PICKED),SUM(A.RESERVPHYSICAL),SUM(A.RESERVORDERED),SUM(A.ONORDER),SUM(A.ORDERED),SUM(A.ARRIVED),SUM(A.QUOTATIONRECEIPT),SUM(A.QUOTATIONISSUE),SUM(A.PHYSICALINVENT),SUM(A.JSPOTENCIES),SUM(A.JSPOTENCIES2_),SUM(A.JSPOSTEDDUALUNITQTY),SUM(A.JSPICKEDDUALUNITQTY),SUM(A.JSRECEIVEDDUALUNITQTY),SUM(A.JSDEDUCTEDDUALUNITQTY),SUM(A.JSREGISTEREDDUALUNITQTY),SUM(A.AVAILPHYSICAL),SUM(A.AVAILORDERED),A.ITEMID,B.CONFIGID,B.INVENTSIZEID,B.INVENTCOLORID,B.INVENTLOCATIONID,B.WMSLOCATIONID 
FROM INVENTSUM A, INVENTDIM B WITH(INDEX(I_698DIMIDIDX)) 
WHERE ((A.DATAAREAID=@P1) AND ((A.CLOSED=@P2) AND (A.CLOSEDQTY=@P3))) AND ((B.DATAAREAID=@P4) AND (A.INVENTDIMID=B.INVENTDIMID)) 
GROUP BY A.ITEMID, A.INVENTDIMID, B.CONFIGID,B.INVENTSIZEID,B.INVENTCOLORID,B.INVENTLOCATIONID,B.WMSLOCATIONID 
ORDER BY A.ITEMID, A.INVENTDIMID, B.CONFIGID,B.INVENTSIZEID,B.INVENTCOLORID,B.INVENTLOCATIONID,B.WMSLOCATIONID
OPTION(FAST 1);

open cur;
fetch next from cur;

close cur;
deallocate cur;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...