SQL Server 2008包含列

klo*_*ork 2 sql sql-server indexing

我最近在SQL Server索引中发现了包含的列.索引中包含的列占用额外的内存还是存储在磁盘上?

也有人可以指出我将包含不同数据类型的列作为主键中包含的列的性能影响,在我的情况下通常是在?

谢谢.

Gor*_*off 5

我不完全理解这个问题:"索引中包含的列是否会占用额外的内存,还是存储在磁盘上?" 索引存储在磁盘(用于持久性)和内存中(用于使用时的性能).

您的问题的答案是非键列存储在索引中,因此存储在磁盘和内存中,以及索引的其余部分.与索引中的键列相比,包含的列确实具有显着的性能优势.要理解这一优势,您必须了解键值可能会在b树索引结构中多次存储.它们既可以用作树中的"节点",也可以用作"叶子"(后者指向表中的实际记录).非键值仅存储在树叶中,可以大大节省存储空间.

这种节省意味着可以在存储器受限的环境中将更多的索引存储在存储器中.并且索引占用的内存较少,允许内存用于其他事情.

包含列的使用是允许索引成为查询的"覆盖"索引,并且具有最小的额外开销.当查询所需的所有列都在索引中时,索引"覆盖"查询,因此可以使用索引而不是原始数据页.这可以显着节省性能.

有关它们的更多信息,请访问Microsoft 文档.


Ban*_*yan 5

在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
Run Code Online (Sandbox Code Playgroud)

存储过程脚本

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
Run Code Online (Sandbox Code Playgroud)

使用上述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
Run Code Online (Sandbox Code Playgroud)

现在运行以下查询

select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile --Takes about 30-50 seconds and return 200,000 results.
Run Code Online (Sandbox Code Playgroud)

查询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.
Run Code Online (Sandbox Code Playgroud)

现在删除上面的非聚集索引并使用以下脚本重新创建

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
Run Code Online (Sandbox Code Playgroud)

它将抛出以下错误 消息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
Run Code Online (Sandbox Code Playgroud)

现在运行以下查询

select UIDNO,FName,DOB, MaritalStatus, Detail1 from dbo.Profile --Takes about 20-30 seconds and return 200,000 results.
Run Code Online (Sandbox Code Playgroud)

查询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.
Run Code Online (Sandbox Code Playgroud)