MS SQL Server(バージョン2005を使用しています)の列または列の数にインデックスを作成する場合、各列のインデックスが昇順または降順のいずれかになるように指定できます。なぜこの選択がここにもあるのか理解するのに苦労しています。バイナリソートテクニックを使用すると、ルックアップはどちらの方法でも同じくらい速くありませんか?どの順序を選択すると、どのような違いがありますか?
MS SQL Server(バージョン2005を使用しています)の列または列の数にインデックスを作成する場合、各列のインデックスが昇順または降順のいずれかになるように指定できます。なぜこの選択がここにもあるのか理解するのに苦労しています。バイナリソートテクニックを使用すると、ルックアップはどちらの方法でも同じくらい速くありませんか?どの順序を選択すると、どのような違いがありますか?
回答:
これは主に複合インデックスで使用する場合に重要です。
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を構成する列は、常にそのテーブルの他のインデックスの末尾の列です。
真の単一列インデックスの場合、クエリオプティマイザーの観点からほとんど違いはありません。
テーブル定義について
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 %% )