У мене є запит, коли використання 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 *запит, без підказки.