2016-05-10 16 views
0

同じ列の2つの別々のインデックスを持つDB内のテーブルが見つかりました。列のタイプはintで、この列にはクラスター化された主キーがあります。これに加えて、同じ列に一意の非クラスター化インデックスがあります。インデックスには同じオプション(並べ替え方向など)があり、含まれる列は含まれません。クラスタ化されたインデックスとクラスタ化されていないインデックスのパフォーマンスの差

このインデックスは、他のテーブルの外部キー制約によって使用されるため、外部キー制約を再作成することなく削除できません。

これには正当な理由がありますか?

+0

外部キー制約が1つのインデックスを使用し、他のインデックスは使用しないとはどういう意味ですか?この目的のためにインデックスはどのように定義されていますか?非クラスタ化インデックスは削除できます。 –

+0

私は、「明示的なDROP INDEXはインデックス 'dbo.Table.IX_Index'に許可されていません。これはFOREIGN KEY制約の適用に使用されています」というメッセージが表示されます。 – greatvovan

+0

また、この質問に関連するジェフ・モデンの答えが見つかりました:http://stackoverflow.com/questions/18707037/how-to-find-what-foreign-key-references-an-index-on-tableしかし、何の証拠も見つかりませんでしたorignalのドキュメントで。 – greatvovan

答えて

3

多分効率のためです。ノンクラスタード・インデックスは、リーフ・レベルのクラスタード・インデックスにすべての(非LOB)フィールドが含まれているため、通常、クラスタード・インデックスよりも小さくなります。したがって、非クラスタ化インデックスを使用して外部キー制約を適用する方が望ましいかもしれません。

更新:この理論を踏まえたAdventureWorksデータベースを使用して、さらにテストを行った。下記参照。

2つのテーブルT1とT2を使用して問題を再現できます。 T1は親であり、T2からT1への外部キー関係がある。

T1にクラスタ化されたプライマリキー制約と非クラスタ化一意インデックスIx-T1がある場合、テーブルを変更してクラスタ化されたプライマリキー制約を削除できますが、見つけたときにIx-

クラスタ化されていないプライマリキー制約とクラスタ化一意インデックスIx_T1を使用してT1を作成すると、状況が逆になります。Ix-T1は削除できますが、プライマリキー制約は削除できません。

CREATE TABLE T1 
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED 
); 

CREATE UNIQUE NONCLUSTERED INDEX Ix_T1 
    ON T1(id); 

CREATE TABLE T2 
(
    id2 int NOT NULL PRIMARY KEY CLUSTERED, 
    id1 int NOT NULL FOREIGN KEY REFERENCES dbo.T1(id) 
); 

INSERT INTO T1 (id) 
    VALUES (1), (2), (3), (4); 

INSERT INTO T2 (id2, id1) 
    VALUES (11, 1), (12, 2), (13, 3); 

ノンクラスタード・インデックスを削除してみます。これは失敗します。

enter image description here

DROP INDEX Ix_T1 
    ON dbo.T1; 

は、しかし、私は、クラスタ化された主キー制約を削除することができます。

ALTER TABLE dbo.T1 
    DROP CONSTRAINT PK_T1; 

enter image description here

T1は、非クラスタ化主キーとクラスタ固有のインデックスを有するテストを繰り返します。

CREATE TABLE T1 
(
    id int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY NONCLUSTERED 
); 

CREATE UNIQUE CLUSTERED INDEX Ix_T1 
    ON T1(id); 

今回は、主キー制約を削除できません。

enter image description here

ALTER TABLE dbo.T1 
    DROP CONSTRAINT PK_T1; 

は、しかし、私は、クラスタ化インデックスを削除することができます。

DROP INDEX Ix_T1 
    ON dbo.T1; 

enter image description here

私の理論が正しければ、あなたが非クラスタ化インデックスを削除するのであれば、パフォーマンスが低下する可能性があります。いくつかの調査とテストが必要な場合があります。

インデックスが存在する理由を説明するデータベーススキーマのドキュメントはありますか?あるいはデータベースを設計した人に尋ねることができますか?

私はAdventureWorks2014を使用していくつかのテストを行いました。テストのための

USE AdventureWorks2014; 
GO 
CREATE SCHEMA test; 
GO 

-- Create two test tables 
SELECT * 
    INTO test.SalesOrderHeader 
    FROM Sales.SalesOrderHeader; 

SELECT * 
    INTO test.SalesOrderDetail 
    FROM Sales.SalesOrderDetail; 

-- Test 1 - Clustered primary key and nonclustered index 
ALTER TABLE test.SalesOrderHeader 
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY CLUSTERED (SalesOrderID); 

CREATE UNIQUE NONCLUSTERED INDEX Ix_Test_SalesOrderHeader 
    ON test.SalesOrderHeader(SalesOrderID); 

-- Test 2 - Nonclustered primary key and clustered index 
CREATE UNIQUE CLUSTERED INDEX Ix_Test_SalesOrderHeader 
    ON test.SalesOrderHeader(SalesOrderID); 

ALTER TABLE test.SalesOrderHeader 
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY NONCLUSTERED (SalesOrderID); 

-- Test 3 - Clustered primary key only 
ALTER TABLE test.SalesOrderHeader 
    ADD CONSTRAINT PK_Test_SalesOrderHeader PRIMARY KEY CLUSTERED (SalesOrderID); 

-- Same for all tests 
ALTER TABLE test.SalesOrderDetail 
    ADD CONSTRAINT PK_Test_SalesOrderDetail PRIMARY KEY CLUSTERED (SalesOrderDetailID); 

ALTER TABLE test.SalesOrderDetail 
    ADD CONSTRAINT FK_Test_SalesOrderDetail_SalesOrderHeader FOREIGN KEY (SalesOrderID) REFERENCES test.SalesOrderHeader(SalesOrderID); 

-- Update 100 records in SalesOrderDetail 
UPDATE test.SalesOrderDetail 
    SET SalesOrderID = SalesOrderID + 1 
    WHERE SalesOrderDetailID BETWEEN 57800 AND 57899; 

実際の実行計画1.

enter image description here

テスト2.インデックスシークオペレータの推定サブツリーコストの実際の実行計画をテストすることがほとんど同じである1

enter image description here

テスト3の実際の実行計画。インデックスシークの推定サブツリーコストはmoです。ここでは、二重テスト1またはテスト2より

enter image description here

、再インデックスのサイズを計測するクエリです。 (テスト1の構成。)クラスタード・インデックスがはるかに大きいことがはっきり分かります。ここで

enter image description here

-- Measure sizes of indexes 
SELECT I.object_id, I.name, I.index_id, I.[type], I.[type_desc], SUM(s.used_page_count) * 8 AS 'IndexSizeKB' 
    FROM sys.indexes AS I 
     INNER JOIN sys.dm_db_partition_stats AS S 
      ON S.[object_id] = I.[object_id] AND S.index_id = I.index_id 
    WHERE I.[object_id] = OBJECT_ID('test.SalesOrderHeader') 
    GROUP BY I.object_id, I.name, I.index_id, I.[type], I.[type_desc]; 

は、クラスタ化インデックスと非クラスタ化インデックスを説明するいくつかの参照です。

のTechNet>テーブルとインデックスのデータ構造のアーキテクチャ:https://technet.microsoft.com/en-us/library/ms180978(v=sql.105).aspx

トレーニングキット70から462の管理のMicrosoft SQL Server 2012のデータベース>第10章:インデックスと同時実行>レッスン1:実装と保守インデックス

のMicrosoft SQL Server 2012 Internals by Kalen Delaney>第7章:インデックス:内部と管理

+0

NCIがCIよりも効率的であるという証拠を提供できますか?サイズについて:この記事は、NCIがCIよりも多くのスペースを必要とすることを示しています。http://www.sqlserverlogexplorer.com/overview-of-cluster-and-noncluster-index/ディスク上のサイズは効率の要素にはなりません検索時に完全に読み取られません。 – greatvovan

+1

あなたが指している記事は非常に簡単です。彼の非クラスタ化インデックスの記述は混乱します。ヒープ上の非クラスタ化インデックスとクラスター化インデックスの区別はしません。ノンクラスタード・インデックスがクラスタード・インデックスよりもスペースを必要とするという彼の陳述は間違っています。葉レベルのクラスタ化インデックスは、葉ノードにすべての非LOBフィールドが含まれているため、非クラスタ化インデックスにはクラスタ化インデックスまたはヒープへのポインタが含まれているため、より多くの領域が使用されます。 – RichardCL

+1

私はテーブルとインデックスを説明する私の答えに3つの参照を追加しました。 – RichardCL

関連する問題