Amankeldi
Дата: 05.02.2013 12:52:49
select dc.Id as DcId,
(case when dc.Conclusion = 0 then N'Не пройден' else N'Пройден' end) as Result,
isnull(batch.StatusId, 0) as BatchStatusId
from dc.DiagnosticCards as dc inner join
tr.RegDocuments as rd on dc.RegDocumentId = rd.Id inner join
dic.TransportModels as tm on rd.ModelId = tm.Id inner join
dic.TransportBrands as tb on tm.BrandId = tb.Id inner join
dic.TransportCategories as tcat on rd.CategoryId = tcat.Id inner join
dic.TransportColors as tc on rd.ColorId = tc.Id inner join
dic.InspectionCenters as ic on dc.InspectionCenterId = ic.Id inner join
dic.InspectionTypes as it on dc.InspectionTypeId = it.Id inner join
dic.Regions as reg on dc.InspectionRegionId = reg.Id inner join
tic.IssuedTicketDetails as itd on dc.Id = itd.DiagnosticCardId left join
tic.IssuedTickets as ist on itd.TicketId = ist.Id left join
tic.IcTicketRanges as itr on ist.RangeId = itr.Id left join
tic.TiTicketRanges as ttr on itr.RangeId = ttr.Id left join
tic.TicketRanges as tr on ttr.RangeId = tr.Id left outer join
dbo.BatchDc as bdc on bdc.Id = (select top(1) Id from dbo.BatchDc as bdci where bdci.DcId = dc.Id order by bdci.Id desc) left join
dbo.Batch as batch on batch.BatchNumber = bdc.BatchNumber join
dbo.SystemParams as sp on sp.Id = 8
where (bdc.Id is null)
or (batch.StatusId = 3 and datediff(day, batch.BatchDateCreated, getdate()) > 1)
or (batch.StatusId = 4 and datediff(day, batch.BatchDateCreated, getdate()) > 5)
or (batch.StatusId = 5)
or (bdc.StatusId = 4)
or (isnull(dc.ModifiedDate, 0) != isnull(bdc.DcDateUpdated, 0))
or (isnull(tb.ModifiedDate, 0) != isnull(bdc.BrandDateUpdated, 0))
or (isnull(tm.ModifiedDate, 0) != isnull(bdc.ModelDateUpdated, 0))
or (isnull(tcat.ModifiedDate, 0) != isnull(bdc.CategoryDateUpdated, 0))
or (isnull(tc.ModifiedDate, 0) != isnull(bdc.ColorDateUpdated, 0))
or (isnull(ic.ModifiedDate, 0) != isnull(bdc.InspCenterDateUpdated, 0))
or (isnull(rd.ModifiedDate, 0) != isnull(bdc.RegDocumentsDateUpdated, 0))
Можно ли перезаписать этот запрос, чтобы набор возвращаемых данных был те же, но время выполнение запроса был быстрее? Если можно, то как?
aleks2
Дата: 05.02.2013 13:14:41
Куды ж те стока OR в where?
Crimean
Дата: 05.02.2013 14:14:37
2 Amankeldi
- проверить планы на отсутствие convert для полей входящих в индексы. если есть - причесать типы данных с включением головы
- проверить, чтобы join были по уникальным наборам полей. если нет - переосмыслить
- вот это, возможно, заменить на outer apply, что даст 1 обращение к dbo.BatchDc для получения всех ее полей:
outer join
dbo.BatchDc as bdc on bdc.Id = (select top(1) Id from dbo.BatchDc as bdci where bdci.DcId = dc.Id order by bdci.Id desc)
- такое число OR + параметризация в WHERE намекают как минимум на option( recompile ) для получения оптимальных планов для разного числа определенных / разных значений параметров
- вот это:
or (batch.StatusId = 3 and datediff(day, batch.BatchDateCreated, getdate()) > 1)
or (batch.StatusId = 4 and datediff(day, batch.BatchDateCreated, getdate()) > 5)
"инвертировать" как условие для в смысле превратить в "batch.BatchDateCreated > " - проще же сделать dateadd( getdate())
- вообще по возможности сократить "константную" часть WHERE, полностью зависящую от входных параметров, сиквел это делает хреново (весь этот мусор будет всегда вычисляться)
- вот этот ужас переосмыслить и переписать без isnull. ибо "or" + "!=" + применение функции к полю = куча-море "вычислений после", а нам нужны "сравнения до"
or (isnull(dc.ModifiedDate, 0) != isnull(bdc.DcDateUpdated, 0))
or (isnull(tb.ModifiedDate, 0) != isnull(bdc.BrandDateUpdated, 0))
or (isnull(tm.ModifiedDate, 0) != isnull(bdc.ModelDateUpdated, 0))
or (isnull(tcat.ModifiedDate, 0) != isnull(bdc.CategoryDateUpdated, 0))
or (isnull(tc.ModifiedDate, 0) != isnull(bdc.ColorDateUpdated, 0))
or (isnull(ic.ModifiedDate, 0) != isnull(bdc.InspCenterDateUpdated, 0))
or (isnull(rd.ModifiedDate, 0) != isnull(bdc.RegDocumentsDateUpdated, 0))
iap
Дата: 05.02.2013 14:32:36
Crimean |
---|
or (isnull(dc.ModifiedDate, 0) != isnull(bdc.DcDateUpdated, 0)) or (isnull(tb.ModifiedDate, 0) != isnull(bdc.BrandDateUpdated, 0)) or (isnull(tm.ModifiedDate, 0) != isnull(bdc.ModelDateUpdated, 0)) or (isnull(tcat.ModifiedDate, 0) != isnull(bdc.CategoryDateUpdated, 0)) or (isnull(tc.ModifiedDate, 0) != isnull(bdc.ColorDateUpdated, 0)) or (isnull(ic.ModifiedDate, 0) != isnull(bdc.InspCenterDateUpdated, 0)) or (isnull(rd.ModifiedDate, 0) != isnull(bdc.RegDocumentsDateUpdated, 0)) |
AND NOT EXISTS
(
SELECT dc.ModifiedDate,tb.ModifiedDate,tm.ModifiedDate,tcat.ModifiedDate,tc.ModifiedDate,ic.ModifiedDate,rd.ModifiedDate
INTERSECT
SELECT bdc.DcDateUpdated,bdc.BrandDateUpdated,bdc.ModelDateUpdated,bdc.CategoryDateUpdated,bdc.ColorDateUpdated,bdc.InspCenterDateUpdated,bdc.RegDocumentsDateUpdated
)
Гость333
Дата: 05.02.2013 14:37:54
Amankeldi,
А с какой целью делается "join dbo.SystemParams"? Вроде бы нигде эта таблица не используется.
Crimean |
---|
вообще по возможности сократить "константную" часть WHERE, полностью зависящую от входных параметров |
А что в этом запросе является входными параметрами? Вроде ничего похожего на параметры в тексте запроса не видно.
Crimean
Дата: 05.02.2013 15:05:31
Гость333 |
---|
А что в этом запросе является входными параметрами? Вроде ничего похожего на параметры в тексте запроса не видно. |
точно. провтыкал
recompile убираем - он "мимо кассы"
outer apply оставляем - лишнее обращение уйдет
intersect пробуем - возможно будет "интереснее", с нуловостью он вроде корректен
дальше - смотреть на таблички (размеры, селективности), возможно поможет что-то типа option( force order ), если оптимизатор запутается (а с него станется - запрос не самый простой) в порядке применения соединений
Amankeldi
Дата: 05.02.2013 16:37:15
Огромное спасибо за советы! Попробую....
iap
Дата: 05.02.2013 16:53:20
Только вот ещё: надо подобрать порядок JOINов, если FORCE ORDER.
Да и без него, вообще-то, тоже.
Очень всё зависит при таком количестве этих самых JOINов...
Надо постараться в начало переставить по возможности маленькие таблицы и далее по возрастанию.
Ну и не напортачить с порядком INNER/LEFT, естественно.
Crimean
Дата: 05.02.2013 17:02:29
и еще добавлю - сама по себе выборка "безперспективная" ибо шансов особо нету у сервера ее эффективно выполнить при текущей "постановке задачи"
пример
скажем, когда есть табличка Table1 с полем Column1 и с индексом на это поля - тогда запрос вида
select * from Table1 where Column1 = @Value1
понятно как выполнять - взять кусочек данных по индексу
а у вас же все условно сводится к ситуации табличка Table1 с полями Column1, Column2 и запрос вида
select * from Table1 where Column1 = Column2
и как серверу это "оптимизировать"? правильно - никак - только все просканить и сравнить