1

私は、次の構造を持つ非常に大きなテーブル (1 日あたり約 270 万行が追加される) に取り組んでいます。

CREATE TABLE [dbo].[Result](
    [ResultDate] [date] NOT NULL,
    [Thing1Id] [int] NOT NULL,
    [Num] [int] NOT NULL,
    [Thing2Id] [int] NOT NULL,
CONSTRAINT [PK_Result] PRIMARY KEY CLUSTERED 
(
    [ResultDate] ASC,
    [Thing1Id] ASC,
    [Num] ASC
))

クラスター化された主キーは ResultDate、Thing1Id、および Num にあるため、次のクエリが最適であると予想されます。

SELECT Thing2.* 
FROM dbo.Result
INNER JOIN Thing2 ON Thing2.Id = result.Thing2Id
WHERE 
    ResultDate >= '2012-01-01'
    AND
    ResultDate <= '2012-01-30'
    AND Thing1Id = 23

ご覧のとおり、クエリは特定の Thing1 について 1 月 12 日に結果を見つけています。

ただし、実行計画は、次のインデックスを追加することでパフォーマンスが大幅に向上することを示しています。

CREATE NONCLUSTERED INDEX [IX_Missing]
ON [dbo].[Result] ([Thing1Id],[ResultDate])
INCLUDE ([Num],[Thing2Id]) 

確かに、このインデックスを追加すると、パフォーマンスが大幅に向上します。

誰かが理由を説明してもらえますか? 私の知る限り、クラスター化された主キーを使用して結果を十分に絞り込む必要があります。これを追加すると、インデックスのサイズがはるかに大きくなり、不要なオーバーヘッドが追加されます。

パフォーマンスを向上させるために、テーブルに異なるインデックスを付けることはできますか?

(実際には、テーブルは実際には結合された 2 つのテーブルであり、データは毎日一方から他方にシフトされ、データは毎月分割されることに注意してください)。

4

3 に答える 3

0

ResultDateで範囲検索を実行しているため、PKはクエリに最適ではありません。クエリを使用して、Thing1Id23の検索を約に絞り込みます。まだたくさんある8100万行。

クエリでは、Thing1Idの検索は23に固定されているため、Thing1IdとResultDateの追加のインデックスがクエリに最適になります。

于 2012-12-05T11:36:26.340 に答える
0

インデックスは基本的に「キー」でテーブルを配置します。あなたの場合、「thing1ID」、「ResultDate」です。テーブルがソートされている場合、行へのアクセスはテーブル全体をループするよりもはるかに高速です (2.7mil)。

つまり、2,7,3,8,1 の場合、番号 1 を取得するにはテーブル全体を検索する必要があります。ただし、1、2、3、7、8 の場合は、最初の番号だけをチェックします。

しかし!「キー」を含む多くの更新/挿入があるテーブルの場合、すべてのエントリの後にテーブルをソートする必要があるため、速度が低下します。したがって、DB に最適なものを見つけてください。

于 2012-12-05T10:59:00.713 に答える
0

クエリ実行プランは、ここで何が起こっているかを特定するものであり、通常は推測よりもはるかに優れていますが、この場合、経験に基づいた推測に十分な情報があると思います.

まず、インデックスのINCLUDE ([Num],[Thing2Id])一部は、これらの 2 つの列の値がインデックスとテーブル自体で重複していることを意味します。そのインデックスでルックアップを実行した後、SQL Server がこれらの詳細をテーブル自体で検索する必要がなくなるため (この場合、インデックスはカバリング インデックスです)、これは便利ですが、通常、このルックアップは非常に高速であるため、直接行うことはほとんどありません。 「大幅に」改善されたパフォーマンスに責任があります。次のインデックスは 99.9% 高速であると推測します。

CREATE NONCLUSTERED INDEX [IX_Missing]
ON [dbo].[Result]
(
    [Thing1Id],
    [ResultDate]
)

続行する前に、SQL Server がこのクエリを実行する方法が 2 つあることを理解することが重要です (説明のために大幅に簡略化されています)。

  1. ResultDate指定された 2 つの日付の間にあるすべての行を検索し、それらの行を調べてThing1Id、23 の日付がある行を探します。
  2. Thing1Idが 23 であるすべての行を検索し、これらの行を調べてResultDate、指定された 2 つの日付の間にある行を探します。

テーブルに存在するデータに応じて、これらのアプローチの 1 つが他のアプローチよりも大幅にThing1Id高速になる可能性がありResultDateます。最初のアプローチは、より多くの行をより早く排除するためです。

理解する必要があるもう 1 つの重要なパズルのピースは、インデックスの動作方法が原因で、2 番目のケースでは列が列のThing1Id来るため、SQL はクラスター化インデックスを使用できないということです (誰かに依頼するようなものです)。本の索引を使用して、2 番目の文字が「Q」であるすべてのエントリを見つけてから、「S」で始まる単語だけを選択するように依頼します) ResultDate


Thing1Idしたがって、このインデックスがパフォーマンスを向上させる理由についての私の推測は、SQL Serverがアプローチ 1 よりもアプローチ2 (最初にフィルター処理) を使用する方が効率的であるということです。

これを確認するには、クエリ実行プランを使用できるはずです。

于 2013-06-04T14:52:01.860 に答える