Sql server 2005 索引键列与索引包含列
有人能解释一下这个双索引键列和索引包含列吗 目前,我有一个索引,它有4个索引键列和0个包含列Sql server 2005 索引键列与索引包含列,sql-server-2005,tsql,Sql Server 2005,Tsql,有人能解释一下这个双索引键列和索引包含列吗 目前,我有一个索引,它有4个索引键列和0个包含列 感谢包含的列不构成索引键的一部分,但它们确实存在于索引中。基本上,这些值将被复制,因此存在存储开销,但索引覆盖(即被查询优化器选择)更多查询的可能性更大。这种复制还可以提高查询时的性能,因为数据库引擎可以返回值,而无需查看表本身 只有非聚集索引才能包含列,因为在聚集索引中,每一列都被有效地包含。索引键列是索引b树的一部分。不包含包含的列 取两个指标: CREATE INDEX index1 ON tab
感谢包含的列不构成索引键的一部分,但它们确实存在于索引中。基本上,这些值将被复制,因此存在存储开销,但索引覆盖(即被查询优化器选择)更多查询的可能性更大。这种复制还可以提高查询时的性能,因为数据库引擎可以返回值,而无需查看表本身
只有非聚集索引才能包含列,因为在聚集索引中,每一列都被有效地包含。索引键列是索引b树的一部分。不包含包含的列 取两个指标:
CREATE INDEX index1 ON table1 (col1, col2, col3)
CREATE INDEX index2 ON table1 (col1) INCLUDE (col2, col3)
index1
更适合这种查询:
SELECT * FROM table1 WHERE col1 = x AND col2 = y AND col3 = z
SELECT col2, col3 FROM table1 WHERE col1 = x
SELECT * FROM tableName WHERE column1 = x AND column1 = y AND column1 = z and column4=n
SELECT column1, column2 FROM tableName WHERE column1 = a
而index2
更适合这种查询:
SELECT * FROM table1 WHERE col1 = x AND col2 = y AND col3 = z
SELECT col2, col3 FROM table1 WHERE col1 = x
SELECT * FROM tableName WHERE column1 = x AND column1 = y AND column1 = z and column4=n
SELECT column1, column2 FROM tableName WHERE column1 = a
在第一个查询中,index1
提供了一种快速识别感兴趣行的机制。查询将(可能)作为索引查找执行,然后进行书签查找以检索整行
在第二个查询中,index2
充当覆盖索引。SQL Server根本不必访问基表,因为索引提供了满足查询所需的所有数据<在这种情况下,代码>索引1也可以用作覆盖索引
如果您想要一个覆盖索引,但不想将所有列添加到b-树中,因为您不查找它们,或者因为它们不是允许的数据类型(例如XML),所以无法添加,请使用INCLUDE子句。让我们考虑一下这本书。书中的每一页都有页码。本书中的所有信息都是基于此页码按顺序呈现的。用数据库术语来说,页码就是聚集索引。现在想想本书末尾的词汇表。这是按字母顺序排列的,允许您快速查找特定于页码的词汇表术语所属的。这表示以术语表术语作为键列的非聚集索引 现在假设每页的顶部都显示“章节”标题。如果您想在哪一章中找到术语表术语,您必须查找描述术语表术语的页面,然后打开相应页面,并查看页面上的章节标题。这显然代表了键查找——当您需要从非索引列中查找数据时,您必须找到实际的数据记录(聚集索引)并查看此列值。包含的列有助于提高性能—考虑一下术语表,其中每个章节的标题都包含术语表术语如果您需要找出术语表术语所属的章节-您不需要打开实际页面-您可以在查找术语表术语时找到它。 因此,包含的列与章节标题类似。非聚集索引(术语表)有一个附加属性作为非聚集索引的一部分。索引不是按包含的列排序的-它只是有助于加快查找速度的附加属性(例如,您不需要打开实际页面,因为信息已经在词汇表索引中) 示例: 创建表脚本
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, a page number is the clustered index. Now think about the glossary at the end of the book. This is in alphabetical order and allows 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 look up what page # describes glossary term, next - open the 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 the actual page - you can get it when you look up the glossary term. So included columns are like those chapter titles. Non clustered Index (glossary) has an additional attribute as part of the non-clustered index. Index is not sorted by included columns - it just additional attributes that help to speed up the lookup (e.g. you don''t need to open the actual page because the 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
存储过程脚本
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, a page number is the clustered index. Now think about the glossary at the end of the book. This is in alphabetical order and allows 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 look up what page # describes glossary term, next - open the 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 the actual page - you can get it when you look up the glossary term. So included columns are like those chapter titles. Non clustered Index (glossary) has an additional attribute as part of the non-clustered index. Index is not sorted by included columns - it just additional attributes that help to speed up the lookup (e.g. you don''t need to open the actual page because the 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
现在运行以下查询
select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile
--Takes about 30-50 seconds and return 200,000 results.
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 10-15 seconds and return 36,479 records.
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.
现在删除上面的非聚集索引,并使用以下脚本重新创建
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
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
它将抛出以下错误
Msg 1919,16级,状态1,第1行
表“dbo.Profile”中的列“Detail1”的类型无效,无法用作索引中的键列
因为我们不能使用varchar(Max)数据类型作为键列。
现在使用以下脚本创建包含列的非聚集索引
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
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 30-50 seconds and return 200,000 results.
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 10-15 seconds and return 36,479 records.
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.
包含的列不构成索引键的一部分,但它们确实存在于索引中。基本上,这些值将被复制 下面以两种类型的索引和示例列为例 CREATE clustered INDEX NC_index1 ON tableName (column1, column1, column1,column4) CREATE clustered INDEX NC_index2 ON tableName (column1) INCLUDE (column2, column3,column4) 而NC_index2更适合这种查询:
SELECT * FROM table1 WHERE col1 = x AND col2 = y AND col3 = z
SELECT col2, col3 FROM table1 WHERE col1 = x
SELECT * FROM tableName WHERE column1 = x AND column1 = y AND column1 = z and column4=n
SELECT column1, column2 FROM tableName WHERE column1 = a
因为sql server不允许在数据类型(如XML、文本等)上创建索引我想在其他答案中添加有关索引键列和包含列的更详细信息,以及使用包含列的好处。对于这个答案,我从Markus Winand发布于2019-04-30的一篇文章“密切关注索引包含条款”中获取了信息: 索引键列与包含列的区别的简要概述 要理解include子句,首先必须理解使用 索引最多影响三层数据结构:
- B-树
- B-树叶节点级的双链表
- 桌子