現在、データベースとして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
列clients
、displayAds
、およびadsPictures
からのみ列を取得していますが、machines
とmachineGroups
clients
からデータを取得するため。 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秒しかかからないのに、このクエリの実行に長い時間がかかる理由を見つけようとしています。
これまでの私の試みは次のとおりです。
displayAds
テーブルのインデックスを作成しました。これにより、約1秒の改善が得られ、大きな変化はありません。
CREATE NONCLUSTERED INDEX
[MachineIdIndexIncludeAdsPictureIdDisplayFromDisplayTo] ON [dbo].[DisplyadAds]
(
[MachineId] ASC
)
INCLUDE
(
[AdsPictureId],
[DisplayFrom],
[DisplayTo]
)
GO
adsPictures
テーブルのインデックスを作成しました。何も変わっていません。
CREATE NONCLUSTERED INDEX [IX_AdsPictures_IncludeImageName] ON [dbo].[AdsPictures]
(
[Id] ASC
)
INCLUDE ( [ImageName])
GO
クエリの列adsPict.ImageName
を削除しようとしたところ、実行時間が3秒にまで大幅に改善されました(約72秒の改善!)。列が問題だと思いますが、表示する必要があります。
ImageName
の最大レコード長は36です。主に11〜20程度です。 AdsPictures
テーブルには55行あります。
この問題を解決する方法はありますか?どんな助けでも大歓迎です。
あなたの実際の計画のために私が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のプランのルートノードでこの情報を確認することもできます。
SOS_SCHEDULER_YIELD
wait here について読むことができます。一般的な説明としては、クエリはCPUで6639ミリ秒しか実行できなかったということです。 CPUに接続するのを待つキューに66883ミリ秒かかりました。問題の説明(「ビューの実行には6秒しかかからない」)に基づいて、クエリのパフォーマンスの問題ではなく、サーバーのパフォーマンスの問題があります。もちろん、クエリで使用するCPUをさらに少なくする方法もあるかもしれませんが、サーバーに正しいCPUコア/ DTU /数があることを確認し、CPUを最も多く使用するクエリを調べることで、この問題に取り組みます。サーバー。サーバーの負荷が少ない場合、クエリの実行速度はほぼ12倍になります。
これはあなたが持っているものと同じです。
はい、ビューは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
グループ化に役立つインデックスを追加してみてください。
皮切りに:
CREATE NONCLUSTERED INDEX idx ON dbo.Clients(PartnerId)
この記事を Erik Darling で確認してください。これは、計画の34%の費用がかかる高価なHash Match Aggregateを処理する方法を示しています。