У мене є запит, коли використання select *
не тільки набагато менше читає, але й використовує значно менший час процесора, ніж використання select c.Foo
.
Це запит:
select top 1000 c.ID
from ATable a
join BTable b on b.OrderKey = a.OrderKey and b.ClientId = a.ClientId
join CTable c on c.OrderId = b.OrderId and c.ShipKey = a.ShipKey
where (a.NextAnalysisDate is null or a.NextAnalysisDate < @dateCutOff)
and b.IsVoided = 0
and c.ComplianceStatus in (3, 5)
and c.ShipmentStatus in (1, 5, 6)
order by a.LastAnalyzedDate
У цьому закінчено 2473658 логічних показань, в основному в таблиці B. У ньому було використано 26 562 ЦП і тривало 7 965.
Це генерований план запитів:
На PasteThePlan: https://www.brentozar.com/pastetheplan/?id=BJAp2mQIQ
Коли я переходжу c.ID
на *
, запит закінчується 107,049 логічними читаннями, досить рівномірно розподіленими між усіма трьома таблицями. Він використовував 4266 ЦП і тривав 1147.
Це генерований план запитів:
На PasteThePlan: https://www.brentozar.com/pastetheplan/?id=SyZYn7QUQ
Я намагався використовувати підказки, запропоновані Джо Оббіше, з такими результатами:
select c.ID
без підказки: https://www.brentozar.com/pastetheplan/?id=SJfBdOELm
select c.ID
з підказкою: https://www.brentozar.com/pastetheplan/ ? id = B1W ___ N87
select *
без підказки: https://www.brentozar.com/pastetheplan/?id=HJ6qddEIm
select *
із підказкою: https://www.brentozar.com/pastetheplan/?id=rJhhudNIQ
Використання OPTION(LOOP JOIN)
підказки з " select c.ID
драйвом" різко зменшило кількість читань порівняно з версією без натяку, але це все ще робить приблизно 4 рази кількість прочитаних select *
запитів без будь-яких підказок. Додавання OPTION(RECOMPILE, HASH JOIN)
в select *
запит зробив це виконати набагато гірше , ніж все інше я намагався.
Після оновлення статистики на таблицях та їх індексах за WITH FULLSCAN
допомогою select c.ID
запит працює набагато швидше:
select c.ID
перед оновленням: https://www.brentozar.com/pastetheplan/?id=SkiYoOEUm
select *
перед оновленням: https://www.brentozar.com/ pastetheplan /? id = ryrvodEUX
select c.ID
після оновлення: https://www.brentozar.com/pastetheplan/?id=B1MRoO487
select *
після оновлення: https://www.brentozar.com/pastetheplan/?id=Hk7si_V8m
select *
як і раніше перевищує select c.ID
показник загальної тривалості та загального читання ( select *
має приблизно половину прочитаних), але він використовує більше процесора. Загалом вони набагато ближче, ніж до оновлення, проте плани все ж відрізняються.
Така ж поведінка спостерігається і в 2016 році, що працює в режимі сумісності 2014 року, і в 2014 році. Що може пояснити розбіжність між двома планами? Чи може бути, що "правильні" індекси не створені? Чи може статистика трохи застаріла?
Я намагався переміщувати предикати до ON
частини з'єднання різними способами, але план запитів кожен раз однаковий.
Після відновлення індексу
Я відновив усі індекси на трьох таблицях, задіяних у запиті. c.ID
як і раніше робить найбільше читань (понад удвічі більше *
), але використання процесора становить приблизно половину *
версії. c.ID
Версію також потрапило на даний TempDb сортування ATable
:
c.ID
: https://www.brentozar.com/pastetheplan/?id=HyHIeDO87
*
: https://www.brentozar.com/pastetheplan/?id=rJ4deDOIQ
Я також спробував змусити його працювати без паралелізму, і це дало мені найкращий запит: https://www.brentozar.com/pastetheplan/?id=SJn9-vuLX
Я помічаю кількість виконання операторів ПІСЛЯ великого пошуку індексу, який виконує замовлення, виконаного лише 1000 разів у однопотоковій версії, але значно більше в паралелізованій версії, між 2622 та 4315 виконанням різних операторів.
select c.ID
запит набагато швидше, але він все ще виконує додаткову роботу, яку робитьselect *
запит, без підказки.