1

私はここで少し奇妙なものを持っています。バッチ プロセスを実行するコンソール アプリで Entity Framework Code First を使用しています。コードは一連の日付をループして、毎回ストアド プロシージャを実行します。

現在、約 300 回ループしており、時間の経過とともに各実行が遅くなり、クローリングの最後近くまで遅くなります。

私はメモリプロファイリングを試みましたが、そうではありません。コード例を次に示します。

 _dbContext = new FooContext();
 _barService = new BarService(new GenericRepository<Bar>(), _dbContext);

 for (var date = lastCalculatedDate.AddDays(1); date <= yesterday; date = date.AddDays(1))
 {
     _barService.CalculateWeightings(date);
 }

そして、CalculateWeightings が行うことはすべて (私も nlog を使用しています)

public void CalculateWeightings(DateTime dateTime)
{
    _logger.Info("Calculating weightings for {1}", dateTime);
    Context.Database.ExecuteSqlCommand("EXEC CalculateWeightings @dateTime", new SqlParameter("@dateTime", dateTime);
}

ストアド プロシージャは、テーブルにいくつかのレコードを設定するだけです。複雑なことは何もありません。テーブルには 1000 行が数行あるため、問題はありません。

何かご意見は?

SQLを見たい人のために。それは少し巨大ですが、これが時間の経過とともに遅くなる理由はわかりません. 処理される行数はかなり少ないです。

CREATE PROCEDURE [dbo].[CalculateWeightings]
    @StartDate DateTime,
    @EndDate DateTime,
    @TradedMonthStart DateTime,
    @InstrumentGroupId int
AS
BEGIN
    ---- GET ALL THE END OF DAY PRICINGS FOR MONTHLYS ----
    SELECT 
    ROW_NUMBER() OVER 
                    (
                        PARTITION BY RawTrades.FirstSequenceItemName, 
                        CONVERT(VARCHAR, RawTrades.LastUpdate, 103) 
                        ORDER BY RawTrades.FirstSequenceItemName, RawTrades.LastUpdate DESC
                    ) AS [Row], 
    RawTrades.FirstSequenceItemID AS MonthId, 
    Sequences.ActualStartMonth,
    Sequences.ActualEndMonth,
    RawTrades.FirstSequenceItemName AS [MonthName], 
    CONVERT(VARCHAR, RawTrades.LastUpdate, 103) AS LastUpdate,
    RawTrades.Price
    INTO #monthly
    FROM RawTrades
    INNER JOIN Sequences ON RawTrades.FirstSequenceItemId = Sequences.SequenceItemId AND RawTrades.FirstSequenceId = Sequences.SequenceId
    WHERE RawTrades.FirstSequenceID IN (SELECT MonthlySequenceId FROM Instruments WHERE InstrumentGroupId = @InstrumentGroupId) 
    AND [Action] <> 'Remove'
    AND LastUpdate >= @StartDate
    AND LastUpdate < @EndDate
    AND ActualStartMonth >= @TradedMonthStart
    ORDER BY RawTrades.FirstSequenceItemID, RawTrades.LastUpdate DESC

    ---- GET ALL THE END OF DAY PRICINGS FOR QUARTERLYS ----
    SELECT 
    ROW_NUMBER() OVER 
                    (
                        PARTITION BY RawTrades.FirstSequenceItemName,  
                        CONVERT(VARCHAR, RawTrades.LastUpdate, 103) 
                        ORDER BY RawTrades.FirstSequenceItemName, RawTrades.LastUpdate DESC
                    ) AS [Row], 
    CONVERT(VARCHAR, RawTrades.LastUpdate, 103) AS LastUpdate, 
    Sequences.ActualStartMonth,
    Sequences.ActualEndMonth,
    RawTrades.Price
    INTO #quarterly
    FROM RawTrades
    INNER JOIN Sequences ON RawTrades.FirstSequenceItemId = Sequences.SequenceItemId AND RawTrades.FirstSequenceId = Sequences.SequenceId
    WHERE RawTrades.FirstSequenceID IN (SELECT QuarterlySequenceId FROM Instruments WHERE InstrumentGroupId = @InstrumentGroupId)  
    AND Action <> 'Remove' 
    AND LastUpdate >= @StartDate
    AND LastUpdate < @EndDate
    AND RawTrades.Price > 20
    ORDER BY RawTrades.FirstSequenceItemID, RawTrades.LastUpdate DESC

    ---- GET ALL THE END OF DAY PRICINGS FOR QUARTERLYS ----
    SELECT 
    ROW_NUMBER() OVER 
                    (
                        PARTITION BY RawTrades.FirstSequenceItemName,  
                        CONVERT(VARCHAR, RawTrades.LastUpdate, 103) 
                        ORDER BY RawTrades.FirstSequenceItemName, RawTrades.LastUpdate DESC
                    ) AS [Row], 
    CONVERT(VARCHAR, RawTrades.LastUpdate, 103) AS LastUpdate, 
    Sequences.ActualStartMonth,
    Sequences.ActualEndMonth,
    RawTrades.Price
    INTO #seasonal
    FROM RawTrades
    INNER JOIN Sequences ON RawTrades.FirstSequenceItemId = Sequences.SequenceItemId AND RawTrades.FirstSequenceId = Sequences.SequenceId
    WHERE RawTrades.FirstSequenceID IN (SELECT SeasonalSequenceId FROM Instruments WHERE InstrumentGroupId = @InstrumentGroupId) 
    AND Action <> 'Remove' 
    AND LastUpdate >= @StartDate
    AND LastUpdate < @EndDate
    AND RawTrades.Price > 20
    ORDER BY RawTrades.FirstSequenceItemID, RawTrades.LastUpdate DESC

    ---- BEFORE WE INSERT RECORDS MAKE SURE WE DON'T ADD DUPLICATES ----
    DELETE FROM LiveCurveWeightings
    WHERE InstrumentGroupId = @InstrumentGroupId
    AND CalculationDate = @EndDate

    ---- CALCULATE AND INSERT THE WEIGHTINGS ----
    INSERT INTO LiveCurveWeightings (InstrumentGroupId, CalculationDate, TradedMonth, QuarterlyWeighting, SeasonalWeighting)
    SELECT
    @InstrumentGroupId,
    @EndDate,
    #monthly.ActualStartMonth,
    AVG(COALESCE(#monthly.Price / #quarterly.Price,1)) AS QuarterlyWeighting,
    AVG(COALESCE(#monthly.Price / #seasonal.Price,1)) AS SeasonalWeighting
    FROM #monthly
    LEFT JOIN #quarterly 
        ON #monthly.ActualStartMonth >= #quarterly.ActualStartMonth 
        AND #monthly.ActualEndMonth <= #quarterly.ActualEndMonth 
        AND #quarterly.[Row] = 1
        AND #monthly.LastUpdate = #quarterly.LastUpdate
    LEFT JOIN #seasonal 
        ON #monthly.ActualStartMonth >= #seasonal.ActualStartMonth
        AND #monthly.ActualEndMonth <= #seasonal.ActualEndMonth 
        AND #seasonal.[Row] = 1
        AND #monthly.LastUpdate = #seasonal.LastUpdate
    WHERE #monthly.[Row] = 1
    GROUP BY #monthly.ActualStartMonth

    DROP TABLE #monthly
    DROP TABLE #quarterly
    DROP TABLE #seasonal

END
4

1 に答える 1

0

この問題は、EFトラッキンググラフが大きくなりすぎたことが原因である可能性があります。操作を実行するたびにトラッキンググラフを使用してバッチ操作でコンテキストを再利用する場合は、グラフを列挙する必要があります。数百のアイテムがある場合、これは問題ではありませんが、数千に入ると、大きな問題になる可能性があります。ここでこれに関する私の記事を見て、それが問題と一致すると思うかどうかを確認してください。

下のグラフで挿入操作を見ると、約1000の挿入(追跡がオンの場合)が実行時間の急激な増加を開始していることがわかります。(軸の対数目盛にも注意してください)

ここに画像の説明を入力してください

于 2012-07-20T23:13:46.237 に答える