最近、SQL Server インデックスに列が含まれていることを発見しました。インデックスに含まれる列は余分なメモリを消費しますか、それともディスクに格納されますか?
また、主キーに含まれる列として異なるデータ型の列を含めることのパフォーマンスへの影響を誰かが教えてくれますか?
ありがとう。
最近、SQL Server インデックスに列が含まれていることを発見しました。インデックスに含まれる列は余分なメモリを消費しますか、それともディスクに格納されますか?
また、主キーに含まれる列として異なるデータ型の列を含めることのパフォーマンスへの影響を誰かが教えてくれますか?
ありがとう。
SQL Server 2005 以降のバージョンでは、非クラスター化インデックスのリーフ レベルに非キー列を追加することで、非クラスター化インデックスの機能を拡張できます。
非キー列を含めることで、より多くのクエリをカバーする非クラスター化インデックスを作成できます。これは、非キー列には次の利点があるためです。
• インデックス キー列として許可されていないデータ型である可能性があります。( text、ntext、およびimageを除くすべてのデータ型が許可されます。)
• データベース エンジンは、インデックス キー列の数またはインデックス キーのサイズを計算するときに、それらを考慮しません。非クラスター化インデックスに非キー列を含めて、最大 16 個のキー列と最大900バイトのインデックス キー サイズの現在のインデックス サイズ制限を超えないようにすることができます。
クエリ内のすべての列がキー列または非キー列のいずれかとしてインデックスに含まれている場合、非キー列を含むインデックスを使用すると、クエリのパフォーマンスが大幅に向上します。クエリ オプティマイザーはインデックス内のすべての列の値を見つけることができるため、パフォーマンスが向上します。テーブルまたはクラスター化されたインデックス データにアクセスしないため、ディスク I/O 操作が少なくなります。
例:
Create Table Script
CREATE TABLE [dbo].[Profile](
[EnrollMentId] [int] IDENTITY(1,1) NOT NULL,
[FName] [varchar](50) NULL,
[MName] [varchar](50) NULL,
[LName] [varchar](50) NULL,
[NickName] [varchar](50) NULL,
[DOB] [date] NULL,
[Qualification] [varchar](50) NULL,
[Profession] [varchar](50) NULL,
[MaritalStatus] [int] NULL,
[CurrentCity] [varchar](50) NULL,
[NativePlace] [varchar](50) NULL,
[District] [varchar](50) NULL,
[State] [varchar](50) NULL,
[Country] [varchar](50) NULL,
[UIDNO] [int] NOT NULL,
[Detail1] [varchar](max) NULL,
[Detail2] [varchar](max) NULL,
[Detail3] [varchar](max) NULL,
[Detail4] [varchar](max) NULL,
PRIMARY KEY CLUSTERED
(
[EnrollMentId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ストアド プロシージャ スクリプト
CREATE Proc [dbo].[InsertIntoProfileTable]
As
BEGIN
SET NOCOUNT ON
Declare @currentRow int
Declare @Details varchar(Max)
Declare @dob Date
set @currentRow =1;
set @Details ='Let''s think about the book. Every page in the book has the page number. All information in this book is presented sequentially based on this page number. Speaking in the database terms, page number is the clustered index. Now think about the glossary at the end of the book. This is in alphabetical order and allow you to quickly find the page number specific glossary term belongs to. This represents non-clustered index with glossary term as the key column. Now assuming that every page also shows "chapter" title at the top. If you want to find in what chapter is the glossary term, you have to lookup what page # describes glossary term, next - open corresponding page and see the chapter title on the page. This clearly represents key lookup - when you need to find the data from non-indexed column, you have to find actual data record (clustered index) and look at this column value. Included column helps in terms of performance - think about glossary where each chapter title includes in addition to glossary term. If you need to find out what chapter the glossary term belongs - you don''t need to open actual page - you can get it when you lookup the glossary term. So included column are like those chapter titles. Non clustered Index (glossary) has addition attribute as part of the non-clustered index. Index is not sorted by included columns - it just additional attributes that helps to speed up the lookup (e.g. you don''t need to open actual page because information is already in the glossary index).'
while(@currentRow <=200000)
BEGIN
insert into dbo.Profile values( 'FName'+ Cast(@currentRow as varchar), 'MName' + Cast(@currentRow as varchar), 'MName' + Cast(@currentRow as varchar), 'NickName' + Cast(@currentRow as varchar), DATEADD(DAY, ROUND(10000*RAND(),0),'01-01-1980'),NULL, NULL, @currentRow%3, NULL,NULL,NULL,NULL,NULL, 1000+@currentRow,@Details,@Details,@Details,@Details)
set @currentRow +=1;
END
SET NOCOUNT OFF
END
GO
上記の SP を使用すると、一度に200000 レコードを挿入できます。
列「EnrollMentId」にクラスター化インデックスがあることがわかります。
次に、「UIDNO」列に非クラスター化インデックスを作成します。
脚本
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20140216-223309] ON [dbo].[Profile]
(
[UIDNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
次のクエリを実行します
select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile --Takes about 30-50 seconds and return 200,000 results.
クエリ 2
select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile
where DOB between '01-01-1980' and '01-01-1985'
--Takes about 10-15 seconds and return 36,479 records.
上記の非クラスター化インデックスを削除し、次のスクリプトで再作成します
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20140216-231011] ON [dbo].[Profile]
(
[UIDNO] ASC,
[FName] ASC,
[DOB] ASC,
[MaritalStatus] ASC,
[Detail1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
次のエラー メッセージ 1919、レベル 16、状態 1、行 1 がスローされます テーブル 'dbo.Profile' の列 'Detail1' は、インデックスのキー列として使用するのに無効な型です。
varchar(Max) データ型をキー列として使用できないためです。
次のスクリプトを使用して、列が含まれる非クラスター化インデックスを作成します
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20140216-231811] ON [dbo].[Profile]
(
[UIDNO] ASC
)
INCLUDE ( [FName],
[DOB],
[MaritalStatus],
[Detail1]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
次のクエリを実行します
select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile --Takes about 20-30 seconds and return 200,000 results.
クエリ 2
select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile
where DOB between '01-01-1980' and '01-01-1985'
--Takes about 3-5 seconds and return 36,479 records.
含まれる列は、行の内容がプライマリ インデックスのリーフ ノードに保持されるクラスター化インデックスと同様の機能を提供します。インデックスのキー列に加えて、追加の属性がインデックス テーブルのリーフ ノードに保持されます。
これにより、データベース内の別のページにアクセスすることなく、列の値にすぐにアクセスできます。インデックス内のページ参照を介して間接的にする必要がないことによる改善された応答に対して、インデックス サイズと一般的なストレージの増加にはトレードオフがあります。テーブルに複数のインデックスを追加した場合と同様の影響が生じる可能性があります。
ここから:-
クエリ内のすべての列がキー列または非キー列としてインデックスに含まれている場合、非キー列を含むインデックスを使用すると、クエリのパフォーマンスが大幅に向上します。クエリ オプティマイザーはインデックス内のすべての列の値を見つけることができるため、パフォーマンスが向上します。テーブルまたはクラスター化されたインデックス データにアクセスしないため、ディスク I/O 操作が少なくなります。