2009-04-13 30 views
102

MS SQL Serverのカラムまたはカラム数にインデックスを作成すると(2005年版を使用しています)、各カラムのインデックスを昇順または降順に指定できます。私はこの選択がなぜここにあるのかを理解するのに苦労しています。バイナリソート技術を使用すると、どちらの方法も高速にルックアップされませんか?私はどのような違いがありますか?SQL Serverインデックス - 昇順または降順ですが、どのような違いがありますか?

答えて

105

これは主事項複合インデックスで使用:

SELECT * 
FROM mytable 
ORDER BY 
     col1, col2 DESC 

か::

SELECT * 
FROM mytable 
ORDER BY 
     col1 DESC, col2 

ではなく、ために:

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

はどちらにも使用することができます

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の値が降順にソートされますが、col1の各値内pkの値が昇順にソートされます。

これは、次のクエリことを意味します

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

ix_mytable_col1_descではなくix_mytable_col1により提供することができます。すなわち

、任意のテーブルにCLUSTERED INDEXを構成する列は、常にそのテーブルの他のインデックスの末尾列です。真の単一列索引の場合

+0

あなたが「ないために...」と言うとき、あなたはそれが文句を言わない仕事やパフォーマンスが恐ろしいだろう意味ですか? –

+2

インデックスがクエリに使用されないことを意味します。クエリ自体はもちろん、動作しますが、パフォーマンスは悪くなります。 – Quassnoi

+0

は、最初のセクションでは、第二の例では、 " COL1 DESC、col2にDESC BY ORDER" と言うべきではないのですか? –

8

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

ソート順は、通常、インデックスを作成する列よりはるかに重要ではないことに注意してください(順序が逆の場合は逆順でインデックスを読み取ることができます)。私はめったにインデックスの並べ替え順序を与えることはありませんが、私はインデックスの対象となる列については苦労します。

@Quassnoiは、の場合、great exampleを提供します。

53

それはビューのクエリオプティマイザーの視点から少し違いになります。実行計画に見られるように、テーブル定義

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のスキャンしか並列化できないという点でわずかな違いがあります。

Plan

しかしそれは論理的フラグメンテーションの面で大きな違いを生むことができます。インデクスがキーの降順で作成されているが、新しい行に昇順のキー値が付加されていると、論理的な順序からすべてのページが終了する可能性があります。これは、テーブルをスキャンしてキャッシュに入っていないときのIO読み取りのサイズに大きな影響を与える可能性があります。

は、断片化が

/*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 

以下のスクリプトの

    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 

結果を参照してください。これは、後のページがでキー値を昇順ているためであるという仮定を検証するために、空間結果]タブを使用することが可能です両方の場合。

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 %%) 

enter image description here

+0

が、これは本当にランクで私を助けて、この偉大なTIPのためにあなたにマーティンに感謝して、私は降順のインデックスを持っている場合、私は\ @myvalueが可能な最大値に近い場合indexed_column = \ @myvalueが速いですmytableはからMYCOLUMNを選択し、不思議 – TheGameiswar

+0

を問い合わせます\ @myvalueが可能な最小値まで閉じられている場合よりも優先されます。 –

+0

@ LajosArpadなぜ速いのでしょうか? Bの木はバランスのとれた木です。ツリーの深さは両方の場合に同じです。 –

関連する問題