web-dev-qa-db-ja.com

このクエリの実行に時間がかかるのはなぜですか?

現在、データベースとしてMicrosoft SQL Azure (RTM) - 12.0.2000.8を使用しています。データベースには現在10 DTUがあります。

ここでの考え方は、ビューに基づいてクエリを作成することです。このビューには、5つのテーブル結合を持つ単純なSELECT()構文が含まれています。このビューでは、約6秒間に約253K行の出力が得られます。

CREATE VIEW [dbo].[TopAdsDisplaySumaryView]
AS
SELECT  
        client.Id AS ClientId,      -- (PK, int, not null)
        client.PartnerId,           -- (FK, int, not null)
        adsPict.Id AS AdsPictureId, -- (PK, int, not null)
        adsPict.ImageName,          -- (nvarchar(max), null)
        displayAds.DisplayTo,       -- (datetime, not null)
        displayAds.DisplayFrom      -- (datetime, not null)
FROM      
        dbo.Machines AS machine 
        INNER JOIN dbo.MachineGroups AS machineGroups ON machineGroups.Id = machine.MachineGroupId 
        INNER JOIN dbo.Clients AS client ON client.Id = machineGroups.ClientId 
        INNER JOIN dbo.DisplyadAds AS displayAds ON displayAds.MachineId = machine.Id 
        INNER JOIN dbo.AdsPictures AS adsPict ON adsPict.Id = displayAds.AdsPictureId

enter image description here

clientsdisplayAds、およびadsPicturesからのみ列を取得していますが、machinesmachineGroupsclientsからデータを取得するため。 displayAdsテーブルには、ほとんどのデータがあります。

ここから、データ数が最も多い上位5つのデータを生成します。これはクエリです:

SELECT TOP 5
    adsSum.PartnerId as PartnerId,
    adsSum.ClientId as ClientId,
    adsSum.AdsPictureId as AdsPictureId,
    adsSum.ImageName as ImageName,
    count(*) as TotalDisplay
FROM [dbo].[TopAdsDisplaySumaryView] adsSum
GROUP BY adsSum.PartnerId, adsSum.ClientId, adsSum.AdsPictureId, adsSum.ImageName
ORDER BY TotalDisplay DESC

このクエリの実際の実行計画は次のとおりです。 https://Pastebin.com/CcR9cC5e

このクエリを実行すると、約1分15秒かかります。ビューの実行に6秒しかかからないのに、このクエリの実行に長い時間がかかる理由を見つけようとしています。

これまでの私の試みは次のとおりです。

  1. displayAdsテーブルのインデックスを作成しました。これにより、約1秒の改善が得られ、大きな変化はありません。

    CREATE NONCLUSTERED INDEX 
    [MachineIdIndexIncludeAdsPictureIdDisplayFromDisplayTo] ON [dbo].[DisplyadAds]
    (
        [MachineId] ASC
    )
    INCLUDE 
    (   
        [AdsPictureId],
        [DisplayFrom],
        [DisplayTo]
    )
    GO
    
  2. adsPicturesテーブルのインデックスを作成しました。何も変わっていません。

    CREATE NONCLUSTERED INDEX [IX_AdsPictures_IncludeImageName] ON [dbo].[AdsPictures]
    (
       [Id] ASC
    )
    INCLUDE ( [ImageName])
    GO
    
  3. クエリの列adsPict.ImageNameを削除しようとしたところ、実行時間が3秒にまで大幅に改善されました(約72秒の改善!)。列が問題だと思いますが、表示する必要があります。

ImageNameの最大レコード長は36です。主に11〜20程度です。 AdsPicturesテーブルには55行あります。

この問題を解決する方法はありますか?どんな助けでも大歓迎です。

6
Reynaldi

あなたの実際の計画のために私がXMLで見るものは次のとおりです:

<WaitStats>
<Wait WaitType="SOS_SCHEDULER_YIELD" WaitTimeMs="66883" WaitCount="1649" />
<Wait WaitType="RESOURCE_GOVERNOR_IDLE" WaitTimeMs="56086" WaitCount="3980" />
</WaitStats>
<QueryTimeStats CpuTime="6665" ElapsedTime="73522" />

XMLを見たくない場合は、SSMSのプランのルートノードでこの情報を確認することもできます。

enter image description here

SOS_SCHEDULER_YIELD wait here について読むことができます。一般的な説明としては、クエリはCPUで6639ミリ秒しか実行できなかったということです。 CPUに接続するのを待つキューに66883ミリ秒かかりました。問題の説明(「ビューの実行には6秒しかかからない」)に基づいて、クエリのパフォーマンスの問題ではなく、サーバーのパフォーマンスの問題があります。もちろん、クエリで使用するCPUをさらに少なくする方法もあるかもしれませんが、サーバーに正しいCPUコア/ DTU /数があることを確認し、CPUを最も多く使用するクエリを調べることで、この問題に取り組みます。サーバー。サーバーの負荷が少ない場合、クエリの実行速度はほぼ12倍になります。

3
Joe Obbish

これはあなたが持っているものと同じです。

はい、ビューは6秒で実行されますが、クエリはビューに対して多くの呼び出しを行っています。

解決策は インデックス付きビュー です。列ごとのグループにインデックスを付けます。

CREATE VIEW [dbo].[TopAdsDisplaySumaryView] AS
SELECT  client.Id AS ClientId,      -- (PK, int, not null)
        client.PartnerId,           -- (FK, int, not null)
        adsPict.Id AS AdsPictureId, -- (PK, int, not null)
        adsPict.ImageName           -- (nvarchar(max), null)
FROM    dbo.Machines AS machine 
INNER JOIN dbo.MachineGroups AS machineGroups 
        ON machineGroups.Id = machine.MachineGroupId 
INNER JOIN dbo.Clients AS client 
        ON client.Id = machineGroups.ClientId 
INNER JOIN dbo.DisplyadAds AS displayAds 
        ON displayAds.MachineId = machine.Id 
INNER JOIN dbo.AdsPictures AS adsPict 
        ON adsPict.Id = displayAds.AdsPictureId  

SELECT TOP 5
       adsSum.PartnerId as PartnerId,          -- client
       adsSum.ClientId as ClientId,            -- client
       adsSum.AdsPictureId as AdsPictureId,    -- adsPict
       adsSum.ImageName as ImageName,          -- adsPict
       count(*) as TotalDisplay
FROM [dbo].[TopAdsDisplaySumaryView] adsSum
GROUP BY adsSum.PartnerId, adsSum.ClientId, adsSum.AdsPictureId, adsSum.ImageName
ORDER BY TotalDisplay DESC
1
paparazzo

グループ化に役立つインデックスを追加してみてください。

皮切りに:

CREATE NONCLUSTERED INDEX idx ON dbo.Clients(PartnerId)

この記事を Erik Darling で確認してください。これは、計画の34%の費用がかかる高価なHash Match Aggregateを処理する方法を示しています。

0
pacreely