Jeśli masz włączone rejestrowanie, najlepiej do programu SQL Server, dodaj zdarzenie OnPipelineRowsSent. Możesz wtedy określić, gdzie spędza cały swój czas. Zobacz ten post Twój podsystem IO zostaje zatrzaśnięty i generuje wszystkie te pliki tymczasowe, ponieważ nie jesteś już w stanie przechowywać wszystkich informacji w pamięci (z powodu przekształceń asynchronicznych).
Odpowiednie zapytanie z połączonego artykułu jest następujące. Przegląda zdarzenia w sysdtslog90
(Użytkownicy SQL Server 2008+ zastępują sysssislog
) i przeprowadza na nich analizę czasu.
;
WITH PACKAGE_START AS
(
SELECT DISTINCT
Source
, ExecutionID
, Row_Number() Over (Order By StartTime) As RunNumber
FROM
dbo.sysdtslog90 AS L
WHERE
L.event = 'PackageStart'
)
, EVENTS AS
(
SELECT
SourceID
, ExecutionID
, StartTime
, EndTime
, Left(SubString(message, CharIndex(':', message, CharIndex(':', message, CharIndex(':', message, CharIndex(':', message, 56) + 1) + 1) + 1) + 2, Len(message)), CharIndex(':', SubString(message, CharIndex(':', message, CharIndex(':', message, CharIndex(':', message, CharIndex(':', message, 56) + 1) + 1) + 1) + 2, Len(message)) ) - 2) As DataFlowSource
, Cast(Right(message, CharIndex(':', Reverse(message)) - 2) As int) As RecordCount
FROM
dbo.sysdtslog90 AS L
WHERE
L.event = 'OnPipelineRowsSent'
)
, FANCY_EVENTS AS
(
SELECT
SourceID
, ExecutionID
, DataFlowSource
, Sum(RecordCount) RecordCount
, Min(StartTime) StartTime
, (
Cast(Sum(RecordCount) as real) /
Case
When DateDiff(ms, Min(StartTime), Max(EndTime)) = 0
Then 1
Else DateDiff(ms, Min(StartTime), Max(EndTime))
End
) * 1000 As RecordsPerSec
FROM
EVENTS DF_Events
GROUP BY
SourceID
, ExecutionID
, DataFlowSource
)
SELECT
'Run ' + Cast(RunNumber As varchar) As RunName
, S.Source
, DF.DataFlowSource
, DF.RecordCount
, DF.RecordsPerSec
, Min(S.StartTime) StartTime
, Max(S.EndTime) EndTime
, DateDiff(ms, Min(S.StartTime)
, Max(S.EndTime)) Duration
FROM
dbo.sysdtslog90 AS S
INNER JOIN
PACKAGE_START P
ON S.ExecutionID = P.ExecutionID
LEFT OUTER JOIN
FANCY_EVENTS DF
ON S.SourceID = DF.SourceID
AND S.ExecutionID = DF.ExecutionID
WHERE
S.message <> 'Validating'
GROUP BY
RunNumber
, S.Source
, DataFlowSource
, RecordCount
, DF.StartTime
, RecordsPerSec
, Case When S.Source = P.Source Then 1 Else 0 End
ORDER BY
RunNumber
, Case When S.Source = P.Source Then 1 Else 0 End Desc
, DF.StartTime, Min(S.StartTime);
Za pomocą tego zapytania można było rozpoznać, że komponent Merge Join był komponentem opóźnionym. Dlaczego na tych dwóch serwerach działa inaczej, nie mogę w tym momencie powiedzieć.
Jeśli masz możliwość tworzenia tabeli w systemie docelowym, możesz zmodyfikować swój proces tak, aby miał dwa przepływy danych (i wyeliminować kosztowne komponenty asynchroniczne).
- Pierwszy przepływ danych spowoduje przeniesienie pliku płaskiego i kolumny pochodne i umieszczenie ich w tabeli pomostowej.
- Następnie uruchamiane jest uruchamianie zadania SQL, aby obsłużyć logikę Get Min Date + Delete.
- Wtedy masz drugi przepływ danych, który wysyła zapytanie z tabeli pomostowej i przyciąga go bezpośrednio do miejsca docelowego.