SQL Serverインデックス-昇順または降順、どのような違いがありますか?


138

MS SQL Server(バージョン2005を使用しています)の列または列の数にインデックスを作成する場合、各列のインデックスが昇順または降順のいずれかになるように指定できます。なぜこの選択​​がここにもあるのか理解するのに苦労しています。バイナリソートテクニックを使用すると、ルックアップはどちらの方法でも同じくらい速くありませんか?どの順序を選択すると、どのような違いがありますか?


回答:


136

これは主に複合インデックスで使用する場合に重要です。

CREATE INDEX ix_index ON mytable (col1, col2 DESC);

次のいずれかに使用できます。

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

または:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

、しかしのためではない:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

1つの列のインデックスは、両方の方法で並べ替えに効率的に使用できます。

詳細については、私のブログの記事を参照してください。

更新:

実際、それほど明白ではありませんが、これは単一の列インデックスでも問題になる可能性があります。

クラスター化テーブルの列のインデックスを想像してください:

CREATE TABLE mytable (
       pk INT NOT NULL PRIMARY KEY,
       col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)

上のインデックスは、行への参照とともにcol1順序付けられた値を保持col1します。

テーブルはクラスター化されているため、行への参照は実際にはの値ですpk。また、の各値内で順序付けされますcol1

これは、インデックスの葉が実際にで順序付けられていることを意味し(col1, pk)、次のクエリ:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

並べ替えは必要ありません。

次のようにインデックスを作成すると、

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

の場合、の値はcol1降順で並べ替えられますが、のpk各値内の値はcol1昇順で並べ替えられます。

つまり、次のクエリ:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk DESC

は提供できますが、は提供できix_mytable_col1_descませんix_mytable_col1

つまり、CLUSTERED INDEX任意のテーブルでaを構成する列は、常にそのテーブルの他のインデックスの末尾の列です。


1
「しないで...」と言うとき、それは機能しないか、パフォーマンスが恐ろしいでしょうか?
Neil N

5
つまり、インデックスはクエリに使用されません。もちろんクエリ自体は機能しますが、パフォーマンスは低下します。
Quassnoi、2009

1
最初のセクションで、2番目の例は「ORDER BY col1 DESC、col2 DESC」と言ってはいけませんか?
ミッチウィート

71

真の単一列インデックスの場合、クエリオプティマイザーの観点からほとんど違いはありません。

テーブル定義について

CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] ASC))

クエリ

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

BACKWARD実行プランで確認できるように、スキャン方向で順序付けされたスキャンを使用します。ただし、現在はFORWARDスキャンのみを並列化できるというわずかな違いがあります。

予定

ただし、論理的な断片化の点で大きな違いを生む可能性があります。インデックスが降順のキーで作成され、新しい行に昇順のキー値が追加される場合、すべてのページが論理的な順序から外れる可能性があります。これは、テーブルをスキャンするときにIO読み取りのサイズに深刻な影響を与える可能性があり、キャッシュにはありません。

断片化の結果を見る

                    avg_fragmentation                    avg_fragment
name   page_count   _in_percent         fragment_count   _size_in_pages
------ ------------ ------------------- ---------------- ---------------
T1     1000         0.4                 5                200
T2     1000         99.9                1000             1

以下のスクリプトの場合

/*Uses T1 definition from above*/
SET NOCOUNT ON;

CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] DESC))

BEGIN TRAN

GO
INSERT INTO T1 DEFAULT VALUES
GO 1000
INSERT INTO T2 DEFAULT VALUES
GO 1000

COMMIT

SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 
UNION ALL 
SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 

空間結果タブを使用して、後のページに両方のケースで昇順のキー値があるためであるという仮定を確認することができます。

SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T1
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
UNION ALL
SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T2
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )

ここに画像の説明を入力してください


Martinがこの素晴らしいTIPをありがとう、これはランククエリで本当に
役に立ちました

降順のインデックスがあるかどうかを知り、mytableからmycolumnを選択します。ここで、indexed_column = \ @myvalueは、\ @ myvalueが可能な最小値に近い場合よりも、\ @ myvalueが可能な最大値に近い方が高速です。
Lajos Arpad 2016年

@LajosArpadなぜ速くなるのですか?Bツリーはバランスの取れたツリーです。木の深さはどちらも同じです。
マーティン・スミス

@MartinSmithの深さは同じですが、兄弟の順序が変わらないのではないかと思います
Lajos Arpad

@MartinSmith、兄弟の順序にパフォーマンスのわずかな違いさえある場合、何百万もの選択を実行すると、多次元結合は言うまでもなく合計されます。
Lajos Arpad 2016年

8

個々のレコードではなく、ソートされた大量のデータを取得する場合は、ソート順が重要です。

(質問で提案しているように)通常、並べ替え順序は、インデックスを付ける列よりもはるかに重要ではないことに注意してください(順序が逆の場合、システムはインデックスを逆に読み取ることができます)。私はめったにインデックスのソート順を考えませんが、インデックスでカバーされている列に悩まされます。

@Quassnoiは、それ重要な場合優れた例を提供ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.