@BaJar

Как оптимизировать запрос (nested loops)?

Есть запрос, часть которого поедает очень много ресурсов. Есть ли способ оптимизивать сие чудо?

select 
 distinct 
 d.DocumentID
 --,null
 , c.PatientRef
 , d.DocumentCreationDate as N'Дата створення документу'
		,UserName as N'Користувач, який створив'
                ,DepartmentName as N'Відділ користувача'
		,DocumentKindName as N'Група документу'
		,DocumentTemplateName as N'Назва документу'
		,DocumentDLC  as N'Останнє зберігання документу'
		,case when DocumentApproveStatusRef like N'APR' then N'Так' else N'Ні' end as Approved 
  from Document d 
  join (select CourseID, Patientref from Course) c on c.CourseID = d.CourseRef
  join (select DocumentTemplateID, DocumentTemplateName, DocumentKindRef from DocumentTemplate) dt on dt.DocumentTemplateID = d.DocumentTemplateRef
  join (select UserLogin, UserDepartmentRef, UserName from Users) u  on u.UserLogin=d.DocumentUserRef
  join (select DepartmentID, DepartmentName from Department) de on de.DepartmentID=u.UserDepartmentRef 
  join (select DocumentKindCode, DocumentKindName from DocumentKind) dk on dk.DocumentKindCode=dt.DocumentKindRef
 join (select DocumentRef, DocumentNodeStaticGUIDRef, DocumentNodeValue from DocumentNode) dn1  on dn1.DocumentRef = d.DocumentID  and dn1.DocumentNodeStaticGUIDRef in (  
  'd2c08bd8-3e52-4926-bbdf-4c4d37c968ad',	
 --'a07b13b1-8575-4d5e-afac-3e2b8d6e8171',	
 'bd6947b3-cee1-456c-9fc5-12efad75dec2' 	 

 )
 join (select DocumentRef, DocumentNodeStaticGUIDRef, DocumentNodeValue from DocumentNode) dn2 on dn2.DocumentRef = (select T.[value].value ('.', 'int') from DocumentSettingXML.nodes('/DocumentSetting/PreviousDocumentRef') as T([value]))
 and dn1.DocumentNodeStaticGUIDRef = dn2.DocumentNodeStaticGUIDRef
 where 
 (select T.[value].value ('.', 'int') from DocumentSettingXML.nodes('/DocumentSetting/PreviousDocumentRef') as T([value])) is not null

and 
d.DocumentCreationDate between @StartDate and @EndDate
and DocumentTemplateRef in (2125)
and dn1.DocumentNodeValue = dn2.DocumentNodeValue  --жрёт ресурсы


последняя строка тормозит запрос
5ecbf131b659a690124567.png -редиска, которая мешает жить людям.
  • Вопрос задан
  • 1137 просмотров
Пригласить эксперта
Ответы на вопрос 2
@d-stream
Готовые решения - не подаю, но...
я бы начал с некоего переосмысливания - что же он такого делает
думаю для понимания можно вынести сабселекты в джойнах во временные таблицы в памяти (@table)

ну и посмотреть на предмет distinct в главном селекте - есть большие подозрения что от него можно избавится сгруппировав значения
Ответ написан
unfilled
@unfilled
Я бы начал с того, что убрал все подзапросы, джойнил таблицы напрямую. Скорее всего у этого не будет никакого результата, но читать будет проще.
Второе, что нужно сделать - это избавиться от этого:
join (select DocumentRef, DocumentNodeStaticGUIDRef, DocumentNodeValue from DocumentNode) dn2 on dn2.DocumentRef = (select T.[value].value ('.', 'int') from DocumentSettingXML.nodes('/DocumentSetting/PreviousDocumentRef') as T([value]))
 and dn1.DocumentNodeStaticGUIDRef = dn2.DocumentNodeStaticGUIDRef
 where 
 (select T.[value].value ('.', 'int') from DocumentSettingXML.nodes('/DocumentSetting/PreviousDocumentRef') as T([value])) is not null

Попробуйте выкинуть это в нормальную временную таблицу (не табличную переменную) и делать джойн с ней

Nested Loops далеко не всегда плохо, проблема с ним в этом месте в том, что sql server думает, что вернётся 70 тыщ строк (Estimated Number of Rows), а возвращается (Actual Number of Rows) на несколько порядков больше. Дайте ему временную таблицу по которой он сможет построить статистику и он, скорее всего, сам построит приемлемый план.

Если @StartDate и @EndDate - это переменные, а не параметры SP, попробуйте выполнить запрос в том виде, в котором он есть, но явно подсунув туда даты, без переменных. Если это хранимая процедура и это её параметры, попробуйте выполнить её после sp_recompile. Этот абзац актуален только в том случае, если запрос не всегда работает медленно.

Ну и от distinct надо избавляться, да.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы