1

次のようなサブクエリを作成しました。

select top 1 A
from my_table
where B = some_joined_value_from_outer_query
order by C desc

この部分のパフォーマンスを向上させる非クラスター化インデックスを作成したいと考えています。

ここで 3 つの質問:

  1. インデックス付きの列の正しい順序は何ですか?
  2. また、列 A はインデックス付きの列にする必要がありますか、それとも単にインデックスに含める必要がありますか?
  3. サブクエリなしでこれを書き換えることができますか ( and に注意しtop 1order by descください)、パフォーマンスを向上させることができますか?

編集: クエリは次のとおりです(データ同期プロセスの一部):

SELECT ProductId, (
    SELECT Id 
    FROM [Order]
    WHERE Number = (
        SELECT TOP 1 OrderNumber
        FROM OtherDatabase..ReferenceTable
        WHERE ProductNumber = Product.Number
        ORDER BY [Date] DESC)
    ) AS OrderId
FROM Product
4

3 に答える 3

4

(ア)

CREATE NONCLUSTERED INDEX foo ON dbo.my_table(B, C DESC) INCLUDE (A);

(ロ)

A はWHEREorORDER BYにないので、おそらく d 列のリストにあれば十分ですINCLUDE。なぜなら、それは単に「乗り物に沿って」いるだけであり、キーの一部である必要はないからです。

(ハ)

これ以上の文脈なしに答えることは不可能です。サブクエリだけを含めて、表示されない外部クエリについて尋ねるのはなぜですか?

@Quassnoiとの進行中の会話に関してEDIT 、非クラスター化インデックスの末尾の列のソート方向が、特定のクエリで使用される計画に大きな違いをもたらす可能性があることをすばやく示したかっただけです。次の不自然な例を見てみましょう。

CREATE TABLE dbo.foo1(A INT, B INT, C INT);
CREATE NONCLUSTERED INDEX foo1x ON dbo.foo1(B, C) INCLUDE(A);

CREATE TABLE dbo.foo2(A INT, B INT, C INT);
CREATE NONCLUSTERED INDEX foo2x ON dbo.foo2(B, C DESC) INCLUDE(A);

INSERT dbo.foo1 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id]
FROM sys.all_columns AS c CROSS JOIN sys.all_objects
ORDER BY c.[object_id];

INSERT dbo.foo2 SELECT TOP (500000) c.[object_id], c.[object_id], -1*c.[object_id]
FROM sys.all_columns AS c CROSS JOIN sys.all_objects
ORDER BY c.[object_id];

それでは、これら 2 つの提案されたクエリを実行して、プランを調べてみましょう。

SELECT  A
FROM    (
        SELECT  A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN
        FROM    dbo.foo1
        ) q
WHERE   rn = 1;

SELECT  A
FROM    (
        SELECT  A, ROW_NUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN
        FROM    dbo.foo2
        ) q
WHERE   rn = 1;

dbo.foo1 (C は ASC) に対するクエリのプランは次のとおりです。

ここに画像の説明を入力

ここに画像の説明を入力

そして、私が言及した種類:

ここに画像の説明を入力


dbo.foo2 (C は DESC) に対するクエリのプランは次のとおりです。

ここに画像の説明を入力

ここに画像の説明を入力


ここで、内部クエリに WHERE 句を追加すると (たとえば、WHERE B = -1024577103)、プランはより類似したものになります。ただし、これは、PARTITION BY が不要であること、および外部クエリを B のその値に制限するために何らかのマッチングが必要であることも意味します。ただし、質問の特定のクエリでは、インデックスの各列の並べ替え方向が計画にほとんど影響を与えない可能性がありますが、これは同じインデックスを使用できるすべてのクエリに当てはまるわけではありません。

于 2012-05-18T15:37:04.790 に答える
0

次のように書き換えることができます。

SELECT  m.a
FROM    (
        SELECT  m.a, ROW_NUMBER() OVER (PARTITION BY m.b ORDER BY m.c DESC) RN
        FROM    outer_table o
        JOIN    my_table m
        ON      m.b = o.b
        ) q
WHERE   rn = 1

ただし、サブクエリは実際には高速である可能性があります (またはそうでない場合もあります)。

私のブログでこのエントリを参照してください。

于 2012-05-18T15:41:55.230 に答える
0

順序は重要です。最初の順序である列が最も重要です。

インデックスの選択は、完全に最初の列に基づいています。インデックスは、インデックスにリストされている最初の列がクエリで使用されている場合にのみ使用されると見なされます。したがって、最初の列に一致がなく、列がクエリの JOIN、ORDER BY、または WHERE 句で使用されている場合、インデックスは完全に無視されます。

于 2012-05-18T15:38:57.533 に答える