sql >> データベース >  >> RDS >> Sqlserver

デッドロックを作成するクエリを更新および挿入する

    カーソルは避けてください。そのクエリではカーソルは必要ありませんでした。 SQLはありません 命令型言語(これが、誰もがそれを1つとして使用するために悪い名前になる理由です )-それは設定された言語です。

    最初にできることは、SQLの基本的な実行を高速化することです。クエリの解析/実行にかかる時間が短いほど、デッドロックの可能性が低くなります。

    • すべてのテーブルの前に[dbo]を付けます -これにより、解析段階が最大30%削減されます。
    • テーブルにエイリアスを設定します-計画段階から少し切り取ります。
    • 識別子を引用する可能性があります 物事をスピードアップします。
    • これらは、誰かが異議を唱えることを決定する前の、元SQL-PMからのヒントです。

    CTEを使用して更新するデータを取得してから、UPDATE ... FROM ... SELECTを使用できます。 実際の更新を行うためのステートメント。カーソルはドッグスローであるため、これはカーソルよりも高速になります クリーンセット操作と比較した場合(あなたのような最速の「消火ホース」カーソルでさえ)。更新に費やす時間が少ないということは、デッドロックの可能性が少ないことを意味します。 注:元のテーブルがないため、検証できません。開発DBと照合してください。

    DECLARE @nowTime datetime = convert(datetime, @now, 21);
    
    WITH [DailyAggregates] AS
    (
        SELECT  
            [D].[dailyId] AS [dailyId],
            [D].[spentDaily] AS [spentDaily],
            [D].[impressionsCountCache] AS [impressionsCountCache],
            SUM([I].[amountCharged]) as [sumCharged],
            COUNT([I].[impressionId]) as [countImpressions]
            FROM [dbo].[Daily] AS [D]
                INNER JOIN [dbo].[Impressions] AS [I]
                   ON [I].[dailyId] = [D].[dailyId]
            WHERE [I].[isCharged] = 0
              AND [I].[showTime] < @nowTime 
              AND [D].[isActive] = 1
        GROUP BY [D].[dailyId], [D].[spentDaily], [D].[impressionsCountCache]
    )
    UPDATE [dbo].[Daily]
        SET [spentDaily] = [A].[spentDaily] + [A].[sumCharged],
            [impressionsCountCache] = [A].[impressonsCountCache] + [A].[countImpressions]
        FROM [Daily] AS [D]
        INNER JOIN [DailyAggregates] AS [A]
           ON [D].[dailyId] = [A].[dailyId];
    
    UPDATE [dbo].[Impressions]
    SET [isCharged] = 1 
    WHERE [showTime] < @nowTime 
      AND [isCharged] = 0;
    

    さらに、インデックスでPAGEロックを禁止することもできます。これにより、数行がページ全体をロックする可能性が低くなります(ロックエスカレーションのため、ページ全体をロックする前に、特定の割合の行のみをロックする必要があります)。

    CREATE NONCLUSTERED INDEX [IDX_Impressions_isCharged_showTime] ON [dbo].[Impressions]              
    (
        [showTime] ASC, -- I have a hunch that switching these around might have an effect.
        [isCharged] ASC  
    )
    WITH (ALLOW_PAGE_LOCKS = OFF)
    ON [PRIMARY] 
    GO
    

    これにより、デッドロックの可能性が軽減されます。 @nowを過去の日付に制限してみてください(つまり、today - 1 day )挿入された行が更新述語に該当しないことを確認します。デッドロックを完全に防ぐ可能性があります。



    1. MSQL:新しいエントリが高い場合にのみエントリを上書きするにはどうすればよいですか?それ以外の場合は、新しいエントリを作成します

    2. Cosh()がPostgreSQLでどのように機能するか

    3. get_result()mysqlndが有効になっていても機能しません

    4. mysqlクエリを使用して、を除くすべてを選択します