Я пишу приложение, которое запрашивает базу данных стороннего приложения.
Мое приложение создает «библиотеку» представлений SQL в сторонних БД, поэтому мои последующие запросы гораздо проще писать и читать. (Не только из-за логики домена моего приложения, но и потому, что сторонняя БД использует ужасные имена для таблиц и столбцов.)
Я заметил, что одно из моих представлений (которое объединяет другие представления, которые в свою очередь объединяют другие представления ...) демонстрирует необычную медлительность в системе клиента. Я разбил его на более мелкие части, но не смог понять ни одного подозреваемого.
Ниже приведена уменьшенная версия представления, при этом другие виды, на которые оно обычно ссылается, превращаются в CTE, что все еще точно так же медленно, как и исходное представление. Если я разобью его на более мелкие части, они будут выполняться очень быстро. Я также добавил несколько комментариев, показывающих примеры небольших изменений, которые делают запрос намного быстрее.
-- The query takes about 5s when the server has no other load
-- That's too slow because the UI of the app needs the results
with
orderLines as (
select r.DocEntry as rdrDocId,
r1.LineNum as rdrLineId
from rdr1 r1
join ordr r on r.DocEntry = r1.DocEntry
-- If I filter only by LineStatus or only by DocStatus here, query takes <1s
where r1.LineStatus = 'O' and r.DocStatus = 'O'
),
picklistDetails as (
select U_KommNr as pklDocId,
max(cast(U_Space as int)) as maxPlace
from [@PICKING]
where U_DeletedF = 'N'
group by U_KommNr
),
picklistDocs as (
select p.AbsEntry as pklDocId,
case
when pd.maxPlace is null then 0
else pd.maxPlace
end as pklDocMaxPlace
from opkl p
left join picklistDetails pd on pd.pklDocId = p.AbsEntry
),
picklistDocLines as (
select AbsEntry as pklDocId,
PickEntry as pklLineId,
OrderEntry as rdrDocId,
OrderLine as rdrLineId
from PKL1
)
select p.pklDocMaxPlace
from picklistDocs p
join picklistDocLines p1 on p.pklDocId = p1.pklDocId
join orderLines r1 on r1.rdrDocId = p1.rdrDocId
and r1.rdrLineId = p1.rdrLineId
-- If I force parallelism by using the following option, query takes <1s
--option(querytraceon 8649)
В дополнение к тому факту, что все части запроса выполняются довольно быстро в изоляции, я также получаю гораздо более быстрое время выполнения (опять же <1 с в общем), когда я использую <code>#temp таблицы вместо CTE, как показано ниже:
-- This batch execution returns the same result but takes <1s
select r.DocEntry as rdrDocId,
r1.LineNum as rdrLineId
into #orderLines
from rdr1 r1
join ordr r on r.DocEntry = r1.DocEntry
where r1.LineStatus = 'O' and r.DocStatus = 'O'
select U_KommNr as pklDocId,
max(cast(U_Space as int)) as maxPlace
into #picklistDetails
from [@PICKING]
where U_DeletedF = 'N'
group by U_KommNr
select p.AbsEntry as pklDocId,
case
when pd.maxPlace is null then 0
else pd.maxPlace
end as pklDocMaxPlace
into #picklistDocs
from opkl p
left join #picklistDetails pd on pd.pklDocId = p.AbsEntry
select AbsEntry as pklDocId,
PickEntry as pklLineId,
OrderEntry as rdrDocId,
OrderLine as rdrLineId
into #picklistDocLines
from PKL1
select p.pklDocMaxPlace
from #picklistDocs p
join #picklistDocLines p1 on p.pklDocId = p1.pklDocId
join #orderLines r1 on r1.rdrDocId = p1.rdrDocId
and r1.rdrLineId = p1.rdrLineId
Может кто-нибудь разобраться в поведении SQL Server здесь? На мой взгляд, это похоже на ошибку / сбой в оптимизаторе запросов.
Если я не смогу найти способ сделать представление таким же быстрым, каким оно должно быть, я, вероятно, просто превращу его в процедуру, которая использует #temp
таблицы, как во втором вставленном мной коде, но оптимально Я хотел бы избежать этого. У меня есть десятки просмотров со схожей сложностью, и ни один из них не такой медленный.