web-dev-qa-db-ja.com

最適化によって提案された疑わしい重複インデックス

こんにちは、私は次のSQLサーバーデータベーステーブルを持っています: enter image description here

複合主キーに注意してください。これは3つの理由で行われました。

  • エントリの重複を防ぐ
  • すべてのクエリには3つのキーがすべて含まれるため、クエリのパフォーマンスが向上します。
  • インデックスが必要であり、ランダムIDを導入したくありませんでした。

このテーブルはサイズを考慮して設計されていることにも注意してください。このテーブルには数百万行のデータが格納されます。

私の実際の質問にはこれでOKです。 Azure SQLサーバーを使用してこのデータベースをホストしています。自動チューニングを有効にしました。そして不思議なことに、それはその後、新しいインデックスを作成して作成したことがわかりました。 (下記参照)

enter image description here

同じ列がインデックス付けされているので、今私の考えではこれは重複したインデックスのようです。

これで、テーブルに2つのインデックスができました。

オリジナル(私のPK):

ALTER TABLE [dbo].[SensorDataRaw] ADD  CONSTRAINT [PK_SensorDataRaw] PRIMARY KEY CLUSTERED 
(
    [DateTime] ASC,
    [SensorId] ASC,
    [Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

新しく追加された(Azureチューニングによって自動作成):

CREATE NONCLUSTERED INDEX [nci_wi_SensorDataRaw_DC9789077DA75B4440AC8BFE3E2AA198] ON [dbo].[SensorDataRaw]
(
    [Key] ASC,
    [SensorId] ASC,
    [DateTime] ASC
)
INCLUDE (   [Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO

所見:

  • 新しいインデックスでは、列の順序が逆になっています。
  • 新しいインデックスは一意ではありません
  • 新しいインデックスには値の列が含まれます。

インデックスに関する私の知識は進んでいないので注意してください。

だから私の質問は:

  1. 新しく追加されたインデックスが最初に作成したインデックスよりも優れている理由を誰かが説明できますか?.
  2. 2つのインデックスを削除して、両方のケースをカバーするインデックスを作成するにはどうすればよいですか。これは非常に大規模なデータベースであるため、これらの両方のインデックスが占めるスペースを確保できません。
  3. 多分より良いデザインの代替ですか?

追加情報:

ここではクエリのタイプが重要になると想定しているので、いくつかの例を挙げました。

すべてのクエリには、DateTimeSensorId、およびKeyが含まれます。

シンプルなクエリ:

Select SensorId Where average value for key w is greater than x where time between (y,z)

グラフデータ:

SELECT AVG([Value]) AS 'AvgValue',    
    DATEADD( MINUTE, 
    (DATEDIFF(MINUTE, '1990-01-01T00:00:00', [dbo].[SensorDataRaw].
[DateTime]) / @IntervalInMinutes) * @IntervalInMinutes,
        '1990-01-01T00:00:00'
    )      AS 'TimeGroup'
 FROM [dbo].[SensorDataRaw]
 where 
    [dbo].[SensorDataRaw].[SensorId] = @SensorId
    and [dbo].[SensorDataRaw].[Key] = @KeyValue
    and [dbo].[SensorDataRaw].[DateTime] Between @DateFrom and @DateTo
    and [dbo].[SensorDataRaw].[Value] IS NOT NULL  
  GROUP BY (DATEDIFF(MINUTE, '1990-01-01T00:00:00', [dbo].[SensorDataRaw].
    [DateTime]) / @IntervalInMinutes)
6
Zapnologica

システムが提案するインデックスは、表示したクエリにはるかに適しています。主要な列として、等式述部を持つ列を目指す必要があります。

lastname, firstnameによって注文された電話帳を検討してください。 「Brown」と「Yates」の間の姓と「John」の名を持つすべての人を検索する必要がある場合は、ほとんどの電話帳を読む必要があります。電話帳が代わりにfirstname, lastnameで注文された場合、「John」セクションとセクションの最初の「Brown」を簡単に見つけることができます。次に、lastnameが表示されるまですべての名前を読み取るだけで済みます。 「イェーツ」または新しい名に遭遇した後。

理想的なインデックスではない可能性があります。ただし、クラスター化インデックスのキー列を新しい順序で作成するのではなく、この順序に変更するだけでよい場合もあります。ワークロードの知識に基づいてこれを評価する必要があります。

6
Martin Smith

新しく追加されたインデックスが最初に作成したインデックスよりも優れている理由を誰かが説明できますか

インデックスはclustered oneです。つまり、リーフレベルとしてすべてのデータが含まれています。

サーバーが提供するインデックスは狭いkey fields + included fieldリーフレベル。

クエリに必要なのはkey fields + valueフィールドなので、サーバーによって提供される非クラスター化インデックスで十分であり、サーバーによって、可能な最も狭いカバリングインデックスとして選択されます。

2つのインデックスを削除して、両方のケースをカバーするインデックスを作成するにはどうすればよいですか。

非クラスター化インデックスは削除でき、クラスター化はもちろん1つをカバーします。追加フィールドが2つしかない場合は、非クラスター化に関してdatetime2(2)+ decimal(19,4)を使用します。クラスター化。

1
sepupic

推奨されるインデックスはより狭く、クエリがそのインデックスでカバーされる列のみを処理する場合により効率的になります。

列の順序も異なるため、特定のクエリに対してより効率的になる可能性があります(実行プランを確認しないと確実に判断できません)。列の順序は違いを生みます。

非クラスター化インデックスはその特定のクエリには適しているかもしれませんが、すべてを網羅しているわけではありません。さらに、クラスター化インデックスを削除することはできず、両方を保持しても問題はありません。

2つを試してみて、クラスター化インデックスを強制し、実行プランとIO statsを確認してから、非クラスター化を強制して比較します。

1
David Fowler