2

次のテーブルがあるとします。

Orders
======
OrderID
CustomerID
StatusID
DateCreated

そして、次のクエリがあります。

select CustomerID from Orders where OrderID = 100

select OrderID from Orders where CustomerID = 20

select OrderID, StatusID from Orders where CustomerID = 100 and OrderID = 1000

次のインデックスを作成すると:

create nonclustered index Example
  On dbo.Orders(OrderID,CustomerID)
  Include(StatusID)

1 つのインデックスで 3 つのクエリすべてを最適化できますか? 言い換えれば、複合インデックスは、複合内の項目の 1 つを使用するクエリを改善しますか? それとも、クエリ 1 と 2 を満たすために、それらの列 (つまり、OrderID、CustomerID) だけに個別のインデックスを作成する必要がありますか?

4

3 に答える 3

6

このインデックスは、最初にインデックスの左端の列をシークできないため、2 番目のクエリには役立ちません。

電話帳を考えてみてください。まず、Smith という姓を持つすべての人を検索してみてください。簡単ですよね?ここで、名前が John であるすべての人を検索してみてください。電話帳の「インデックス」の仕組みは、LastName、FirstName です。すべての John を見つけようとしている場合、最初に LastName で並べ替えてもまったく役に立ちません。電話帳全体に目を通す必要があります。John Anderson と John Zolti とその間のすべての名前があるからです。

3 つのクエリすべてを最大限に活用するには、これらが使用されているクエリ形式が 3 つだけであると仮定すると、追加のインデックスを提案する可能性があります。

create nonclustered index Example2
  On dbo.Orders(CustomerID) INCLUDE(OrderID)

(OrderID が主キーの場合は、INCLUDE する必要はありません。)

ただし、インデックスは無料ではないため、これはワークロードに対してテストする必要があります。追加のディスク領域が必要であり、DML クエリを実行しているときに余分な作業を維持する必要があります。繰り返しますが、これは、質問にリストされている 3 つのクエリが使用する唯一の形状であることを前提としています。異なる出力列または異なる where 句を持つ他のクエリがある場合、すべての賭けはオフになります。

于 2012-07-18T18:49:05.700 に答える
3

上記の答えは正しいです。しかし、彼らは1つのことを省略しています。おそらく、ORDER_IDにクラスター化されたインデックスが必要です。また、ORDER_IDでクラスター化インデックスを作成すると、非クラスター化インデックスエントリはクラスター化インデックスがあるテーブルのクラスター化インデックスを指すため、テーブルの非クラスター化インデックスには自動的にその値が含まれます。だからあなたはこれが欲しいでしょう:

create clustered index IX_ORDERS_ORDERID on ORDERS (OrderID)
go
create nonclustered index IX_ORDERS_CustomerID
On dbo.Orders(CustomerID)
Include(StatusID)
go

これで、注文IDまたは顧客IDをすばやく検索でき、すべてのクエリが正常に実行されます。実行計画の見方を知っていますか?SQL Studioでクエリに移動します-実際の実行プランを含めてから、クエリを実行します。使用されているインデックス、シークまたはスキャンのどちらが実行されているかなどのグラフィック表現が表示されます。

于 2012-07-18T19:20:32.653 に答える
1
create nonclustered index Example
  On dbo.Orders(OrderID,CustomerID)
  Include(StatusID)

このインデックスを次のように読みます。 Orders テーブルから OrderID、CustomerID、StatusID のシステム管理コピーを作成します。このコピーを OrderID で注文し、CustomerID との関係を断ち切ります。

select CustomerID from Orders where OrderID = 100

インデックスは OrderID によって並べ替えられるため、最初の適格なレコードをすばやく見つけることができます。最初のレコードが見つかったら、OrderID が 100 ではないレコードが見つかるまでインデックスの読み取りを続けます。その後、停止できます。必要な列はすべてインデックスにあるため、実際のテーブルを参照する必要はありません。すごい!

select OrderID from Orders where CustomerID = 20

インデックスは OrderID 順、次に CustomerID 順に並べられるため、条件を満たすレコードはインデックスのどこにでも表示される可能性があります。最初のレコードが該当する可能性があります (OrderID = 1、CustomerID = 20)。最後のレコードが該当する場合があります (OrderID = 1000000000、CustomerID = 20)。適格なレコードを見つけるには、索引全体を読み取る必要があります。これは悪いです。 マイナーなヘルプ: 必要なすべての列がインデックスにあるため、実際のテーブルを参照する必要はありません。したがって、技術的には、2 番目のクエリはインデックスによって支援されますが、他のクエリが支援されるほどではありません。

select OrderID, StatusID from Orders where CustomerID = 100 and OrderID = 1000 

インデックスは OrderID、次に CustomerID の順に並べられるため、最初の適格なレコードをすばやく見つけることができます。最初のレコードが見つかったら、不適格なレコードが見つかるまでインデックスを読み続けることができます。それならやめましょう。必要な列はすべてインデックスにあるため、実際のテーブルを参照する必要はありません。すごい!


複合インデックスは、複合内の項目の 1 つを使用するクエリを改善しますか?

時々!

それとも、クエリ 1 と 2 を満たすために、それらの列 (つまり、OrderID、CustomerID) だけに個別のインデックスを作成する必要がありますか?

時々そうではありません!

本当の答えは、インデックス宣言内の列の順序がインデックス内のレコードの順序を決定するという事実によって微妙に異なります。いくつかの順序付けによって役立つクエリもあれば、そうでないクエリもあります。CustomerID、OrderID のケースをカバーするために、現在のインデックスをもう 1 つ追加する必要がある場合があります。


「必要なすべての列がインデックスにあるため、実際のテーブルを検索する必要はありません」-つまり、インデックスは読み取り目的で使用できますが、シーク/検索目的では使用できませんか?

インデックス (テーブルの一部のコピー) にクエリの解決に必要なすべての情報が含まれている場合、実際のテーブルを読み取る必要はありません。インデックスはクエリを「カバー」します。

于 2012-07-18T18:59:55.147 に答える