web-dev-qa-db-ja.com

非クラスター化インデックスは使用されていません

321行を含むテーブル(以下に作成)があります。

以下の最後のクエリでは、非クラスター化インデックスを使用してからキールックアップを使用することを期待しています。ただし、代わりにクラスター化インデックススキャンを使用します。期待どおり単一行のみが返されます。

非クラスター化インデックスを使用するのではなく、なぜスキャンを実行するのですか?テーブルに含まれているのは321行しかないためですか?

CREATE TABLE dbo.TestIndexSample
(
    Code char(4) NOT NULL,
    Name nvarchar(200) NOT NULL,
    ModifiedDate datetime NOT NULL CONSTRAINT [DF_TestIndexSample_ModifiedDate] DEFAULT GETDATE(),
    CONSTRAINT [PK_TestIndexSample_Code] PRIMARY KEY CLUSTERED(Code)
);
GO
CREATE NONCLUSTERED INDEX IX_TestIndexSample_Name  
    ON dbo.TestIndexSample(Name);   
GO

INSERT INTO dbo.TestIndexSample(Code, Name)
select CodeName, FullName 
from dbo.SourceTest 
GO

SELECT * FROM dbo.TestIndexSample

SELECT * FROM dbo.TestIndexSample where Code = 'X132EY'

SELECT * FROM dbo.TestIndexSample where Name = 'User A'
3
Kevin

SQL Serverで非クラスター化インデックスを使用するように強制できます。

SELECT Code, Name, ModifiedDate 
FROM   dbo.TestIndexSample WITH(INDEX (IX_TestIndexSample_Name))
WHERE  Name = 'NAME10';

enter image description here

dbfiddle ここ 、計画 ここ

ヒントがないと、クエリオプティマイザはこの少量のデータに対してインデックスのあるプランをよりコストがかかると見なしますが、テーブルの行数を増やすことでこのプランを取得できます。私はなんとか600行でそれを達成しました:

SELECT Code, Name, ModifiedDate 
FROM   dbo.TestIndexSample 
WHERE  Name = 'NAME10';

dbfiddle ここ

インデックスシークのみを取得する場合、クエリはNameのみを返す必要があるため、データはインデックスからのみプルされます。

SELECT Name 
FROM   dbo.TestIndexSample  
WHERE  Name = 'NAME10';

enter image description here

dbfiddle ここ 、計画 ここ

ただし、他の列も返す必要がある場合は、カバリングインデックスを使用できます。

CREATE NONCLUSTERED INDEX IX_TestIndexSample_Name  
    ON dbo.TestIndexSample(Name) INCLUDE (Code, ModifiedDate);

当然、インデックスのサイズは増加しますが、この行数では何も重要ではありません。

これで、現在のクエリはインデックスシークを使用します。

SELECT Code, Name, ModifiedDate 
FROM   dbo.TestIndexSample 
WHERE  Name = 'NAME10';

enter image description here

dbfiddle ここ 、計画 ここ

7
McNets

テーブルに含まれているのは321行しかないためですか?

はいそれは原因であるはずです。

テーブルには何ページありますか?データページが1つしかない可能性が非常に高いため、クラスター化インデックススキャンは、サーバーが2ページだけを読み取ってこの作業を実行できることを意味します。

次のコードを使用してページ数を確認できます。

select index_id, total_pages
from sys.allocation_units au join sys.partitions p
        on au.container_id = p.hobt_id
where p.object_id = object_id('dbo.TestIndexSample');

ここに index_id = 1はクラスター化に対応し、index_id = 2から非クラスター化インデックス。

4
sepupic