翻译: Clustered Index Design Considerations 聚集索引设计注意事项

原文出自:《Pro SQL Server Internals, 2nd edition》的CHAPTER 7 Designing and Tuning the Indexes中的Clustered Index Design Considerations一节(即P155~P165),Dmitri Korotkevitch,侵删

每次更改聚集索引键的值时,都会发生两件事。 首先,SQL Server将行移动到聚集索引页链和数据文件中的不同位置。 其次,它更新了row-id,它是聚集索引键。 存储的行id,需要在所有非聚集索引中更新。 就I / O而言,这可能是昂贵的,特别是在批量更新的情况下。 此外,它可以增加聚集索引的碎片,并且在行ID大小增加的情况下,可以增加非聚集索引的碎片。 因此,最好有一个静态聚集索引,其中键值不会改变。

所有非聚集索引都使用聚集索引键作为row-id。 过宽的聚集索引键会增加非聚集索引行的大小,并且需要更多空间来存储它们。 因此,SQL Server需要在索引或范围扫描操作期间处理更多数据页,这会降低索引的效率。

在非唯一非聚集索引的情况下,row-id也存储在非叶索引级别,这反过来会减少每页索引记录的数量,并可能导致索引中的额外中间级别。 尽管非叶索引级别通常缓存在内存中,但每次SQL Server遍历非聚集索引B-Tree时,这都会引入额外的逻辑读取。

最后,较大的非聚集索引在缓冲池中占用更多空间,并在索引维护期间引入更多开销。 显然,不可能提供一个通用阈值来定义可应用于任何表的密钥的最大可接受大小。 但是,作为一般规则,最好使用窄的聚集索引键,索引键尽可能小。

将聚集索引定义为唯一的也是有益的。 这个很重要的原因并不明显。 考虑一种情况,其中表没有唯一的聚集索引,并且您希望在执行计划中运行使用非聚集索引查找的查询。 在这种情况下,如果非聚集索引中的row-id不是唯一的,则SQL Server将不知道在键查找操作期间要选择哪个聚集索引行。

SQL Server通过向非唯一的c lustered索引添加另一个名为uniquifier的可空整数列来解决此类问题。 对于第一次出现的键值,SQL Server使用NULL填充uniquifier,为插入表中的每个后续副本自动增加它。

■ 注意:每个聚集索引键值的可能重复项数量受整数域值的限制。 具有相同聚集索引键的行不能超过2,147,483,648。 这是理论上的限制,创建具有如此差的选择性的索引显然是个坏主意。

让我们看看非唯一聚集索引中的uniquifiers引入的开销。 清单7-1中显示的代码创建了三个具有相同结构的不同表,并使用每个65,536行填充它们。 表dbo.UniqueCI是唯一定义了唯一聚集索引的表。 表dbo.NonUniqueCINoDups没有任何重复的键值。 最后,表dbo.NonUniqueCDups在索引中有大量重复项。

清单7-1.  非唯一聚簇索引:表创建

 create table dbo.UniqueCI
 (
     KeyValue int not null,
     ID int not null,
     Data char(986) null,
     VarData varchar(32) not null
         constraint DEF_UniqueCI_VarData
         default ‘Data‘
 ); 

create unique clustered index IDX_UniqueCI_KeyValue
 on dbo.UniqueCI(KeyValue); 

create table dbo.NonUniqueCINoDups
 (
     KeyValue int not null,
     ID int not null,
     Data char(986) null,
     VarData varchar(32) not null
         constraint DEF_NonUniqueCINoDups_VarData
         default ‘Data‘
 ); 

create /*unique*/ clustered index IDX_NonUniqueCINoDups_KeyValue
 on dbo.NonUniqueCINoDups(KeyValue); 

create table dbo.NonUniqueCIDups
 (
     KeyValue int not null,
     ID int not null,
     Data char(986) null,
     VarData varchar(32) not null
         constraint DEF_NonUniqueCIDups_VarData
         default ‘Data‘
 ); 

create /*unique*/ clustered index IDX_NonUniqueCIDups_KeyValue
 on dbo.NonUniqueCIDups(KeyValue); 

 -- Populating data
 ;with N1(C) as (select 0 union all select 0) -- 2 rows
 ,N2(C) as (select 0 from N1 as T1 cross join N1 as T2) -- 4 rows
 ,N3(C) as (select 0 from N2 as T1 cross join N2 as T2) -- 16 rows
 ,N4(C) as (select 0 from N3 as T1 cross join N3 as T2) -- 256 rows
 ,N5(C) as (select 0 from N4 as T1 cross join N4 as T2) -- 65,536 rows
 ,IDs(ID) as (select row_number() over (order by (select null)) from N5)
 insert into dbo.UniqueCI(KeyValue, ID)
     select ID, ID from IDs; 

insert into dbo.NonUniqueCINoDups(KeyValue, ID)
     select KeyValue, ID from dbo.UniqueCI; 

insert into dbo.NonUniqueCIDups(KeyValue, ID)
     select KeyValue % 10, ID from dbo.UniqueCI; 

现在,让我们看一下每个表的聚集索引的物理统计信息。 代码如清单7-2所示,结果如图7-1所示。

清单7-2. 非唯一聚集索引:检查聚集索引的行大小

 select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     ,avg_record_size_in_bytes as [avg row size]
 from
      sys.dm_db_index_physical_stats(db_id(), object_id(N‘dbo.UniqueCI‘), 1, null ,‘DETAILED‘); 

select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     , avg_record_size_in_bytes as [avg row size]
 from
      sys. dm_db_index_physical_stats(db_id(), object_id(N‘dbo.NonUniqueCINoDups‘), 1, null ,‘DETAILED‘); 

select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     ,avg_record_size_in_bytes as [avg row size]
 from
      sys. dm_db_index_physical_stats(db_id(), object_id(N‘dbo.NonUniqueCIDups‘), 1, null ,‘DETAILED‘); 

图7-1. 非唯一聚集索引:聚集索引的行大小

即使dbo.NonUniqueCINoDups表中没有重复的键值,仍然有两个额外的字节添加到该行。 SQL Server将一个uniquifier存储在数据的可变长度部分中,并且这两个字节由可变长度数据偏移数组中的另一个条目添加。 在这种情况下,当聚集索引具有重复值时,uniquifiers会再添加另外四个字节,这会产生总共六个字节的开销。

值得一提的是,在某些边缘情况下,uniquifier使用的额外存储空间可以减少可以放入数据页面的行数。 我们的例子说明了这种情况。 如您所见,dbo.UniqueCI使用的数据页数比其他两个表少15%。

现在,让我们看看uniquifier如何影响非聚集索引。 清单7-3中显示的代码在所有三个表中创建非聚集索引。 图7-2显示了这些索引的物理统计信息。

create nonclustered index IDX_UniqueCI_ID
 on dbo.UniqueCI(ID); 

create nonclustered index IDX_NonUniqueCINoDups_ID
 on dbo.NonUniqueCINoDups(ID); 

create nonclustered index IDX_NonUniqueCIDups_ID
 on dbo.NonUniqueCIDups(ID); 

select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     ,avg_record_size_in_bytes as [avg row size]
from
     sys. dm_db_index_physical_stats(db_id(), object_id(N‘dbo.UniqueCI‘), 2, null ,‘DETAILED‘); 

from
     sys. dm_db_index_physical_stats(db_id(), object_id(N‘dbo.NonUniqueCINoDups‘), 2, null ,‘DETAILED‘); 

select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     ,avg_record_size_in_bytes as [avg row size]
from
     sys. dm_db_index_physical_stats(db_id(), object_id(N‘dbo.NonUniqueCIDups‘), 2, null ,‘DETAILED‘); 

select index_level, page_count, min_record_size_in_bytes as [min row size]
     ,max_record_size_in_bytes as [max row size]
     ,avg_record_size_in_bytes as [avg row size] 

图7-2. N个非唯一聚集索引:非聚集索引的行大小

dbo.NonUniqueCINoDups表中的非聚集索引没有开销。您可能还记得,SQL Server不会将偏移信息存储在可变长度偏移数组中,以便存储尾随列空数据。尽管如此,uniquifier在dbo.NonUniqueCIDups表中引入了8个字节的开销。这八个字节由一个四字节的unquifier值,一个双字节的可变长度数据偏移数组条目和一个存储行中可变长度列数的双字节条目组成。

我们可以通过以下方式总结uniquifier的存储开销。对于具有uniquifier为NULL的行,如果索引至少有一个存储NOT NULL值的可变长度列,则会产生两个字节的开销。该开销来自uniquifier列的可变长度偏移数组条目。否则没有开销。

在填充uniquifier的情况下,如果存在存储NOT NULL值的可变长度列,则开销为六个字节。否则,开销是八个字节。

提示:如果预计聚集索引值中存在大量重复项,则可以添加整数标识列作为索引的最右列,从而使其唯一。 与由uniquifiers引入的不可预测的高达8字节的存储开销相比,这为每一行增加了四字节可预测的存储开销。 当您通过其所有聚集索引列引用该行时,这还可以提高单个查找操作的性能。

以最小化插入新行导致的索引碎片的方式设计聚集索引是有益的。实现此目标的方法之一是使聚集索引值不断增加。标识列上的索引就是一个这样的例子。另一个示例是使用插入时的当前系统时间填充的日期时间列。

然而,不断增加的指数存在两个潜在的问题。第一个涉及统计。正如您在第3章中学到的,当直方图中不存在参数值时,SQL Server中的遗留基数估计器会低估基数。您应该将此类行为纳入系统的统计信息维护策略,除非您使用新的SQL Server 2014-2016基数估算器,该估算器假定直方图之外的数据具有与表中其他数据类似的分布。

下一个问题更复杂。随着索引的不断增加,数据总是插入到索引的末尾。一方面,它可以防止页面拆分并减少碎片。另一方面,它可能导致热点,这是当多个会话试图修改相同数据页和/或分配新页面或范围时发生的序列化延迟。 SQL Server不允许多个会话更新相同的数据结构,而是序列化这些操作。

除非系统以非常高的速率收集数据并且索引每秒处理数百个插入,否则热点通常不是问题。我们将在第27章“系统故障排除”中讨论如何检测这样的问题。

最后,如果系统有一组经常执行且重要的查询,那么考虑一个优化它们的聚集索引可能是有益的。这消除了昂贵的密钥查找操作并提高了系统的性能。

即使可以使用覆盖非聚集索引来优化此类查询,但它并不总是理想的解决方案。在某些情况下,它需要您创建非常宽的非聚集索引,这将占用磁盘和缓冲池中的大量存储空间。

另一个重要因素是修改列的频率。将经常修改的列添加到非聚集索引需要SQL Server在多个位置更改数据,这会对系统的更新性能产生负面影响并增加阻塞。

尽管如此,并不总是能够设计满足所有这些准则的聚集索引。此外,您不应将这些指南视为绝对要求。您应该分析系统,业务需求,工作负载和查询,并选择有益于您的聚集索引,即使它们违反了某些准则。

身份,序列和唯一标识符

人们通常选择身份,序列和唯一标识符作为聚集索引键。 与往常一样,这种方法有其自身的优缺点。

在此类列上定义的聚集索引是唯一的,静态的和窄的。 此外,身份和序列不断增加,这减少了索引碎片。 其中一个理想的用例是目录实体表。 作为示例,您可以考虑存储客户,文章或设备列表的表。 这些表存储数千甚至数百万行,尽管数据相对静态,因此热点不是问题。 此外,这些表通常由外键引用并用于连接。 integer或bigint列上的索引非常紧凑和高效,这将提高查询的性能。

■ 注意:我们将在第8章“约束”中更详细地讨论外键约束。

在事务表的情况下,身份或序列列上的聚集索引效率较低,事务表由于它们引入的潜在热点而以非常高的速率收集大量数据。

另一方面,Uniqueidentifiers很少是集群和非集群索引的理想选择。 使用NEWID()函数生成的随机值极大地增加了索引碎片。 此外,uniqueidentifiers上的索引会降低批处理操作的性能。 让我们看一个示例并创建两个表:一个表在标识列上有聚集索引,另一个在uniqueidentifier列上有聚集索引。 在下一步中,我们将在两个表中插入65,536行。 您可以在清单7-4中看到执行此操作的代码。

清单7-4.  Uniqueidentifiers:表创建

create table dbo.IdentityCI
 (
     ID int not null identity(1,1),
     Val int not null,
     Placeholder char(100) null
 ); 

create unique clustered index IDX_IdentityCI_ID
 on dbo.IdentityCI(ID); 

create table dbo.UniqueidentifierCI
 (
     ID uniqueidentifier not null
         constraint DEF_UniqueidentifierCI_ID
         default newid(),
     Val int not null,
     Placeholder char(100) null,
 ); 

create unique clustered index IDX_UniqueidentifierCI_ID
 on dbo.UniqueidentifierCI(ID)
 go 

;with N1(C) as (select 0 union all select 0) -- 2 rows
 ,N2(C) as (select 0 from N1 as T1 cross join N1 as T2) -- 4 rows
 ,N3(C) as (select 0 from N2 as T1 cross join N2 as T2) -- 16 rows
 ,N4(C) as (select 0 from N3 as T1 cross join N3 as T2) -- 256 rows
 ,N5(C) as (select 0 from N4 as T1 cross join N4 as T2) -- 65,536 rows
 ,IDs(ID) as (select row_number() over (order by (select null)) from N5)
 insert into dbo.IdentityCI(Val)
     select ID from IDs; 

;with N1(C) as (select 0 union all select 0) -- 2 rows
 ,N2(C) as (select 0 from N1 as T1 cross join N1 as T2) -- 4 rows
 ,N3(C) as (select 0 from N2 as T1 cross join N2 as T2) -- 16 rows
 ,N4(C) as (select 0 from N3 as T1 cross join N3 as T2) -- 256 rows
 ,N5(C) as (select 0 from N4 as T1 cross join N4 as T2) -- 65,536 rows
 ,IDs(ID) as (select row_number() over (order by (select null)) from N5)
 insert into dbo.UniqueidentifierCI(Val)
     select ID from IDs; 

我的计算机上的执行时间和读取次数如表7-1所示。 图7-3显示了两个查询的执行计划。

图7-3.  将数据插入表中:执行计划

如您所见,uniqueidentifier列上的索引有另一个排序运算符。 SQL Server在插入之前对随机生成的uniqueidentifier值进行排序,这会降低查询的性能。

让我们在表中插入另一批行并检查索引碎片。 执行此操作的代码如清单7-5所示。 图7-4显示了查询的结果。

清单7-5.  Uniqueidentifiers:插入行并检查碎片

 ;with N1(C) as (select 0 union all select 0) -- 2 rows
 ,N2(C) as (select 0 from N1 as T1 cross join N1 as T2) -- 4 rows
 ,N3(C) as (select 0 from N2 as T1 cross join N2 as T2) -- 16 rows
 ,N4(C) as (select 0 from N3 as T1 cross join N3 as T2) -- 256 rows
 ,N5(C) as (select 0 from N4 as T1 cross join N4 as T2) -- 65,536 rows
 ,IDs(ID) as (select row_number() over (order by (select null)) from N5)
 insert into dbo.IdentityCI(Val)
     select ID from IDs; 

;with N1(C) as (select 0 union all select 0) -- 2 rows
 ,N2(C) as (select 0 from N1 as T1 cross join N1 as T2) -- 4 rows
 ,N3(C) as (select 0 from N2 as T1 cross join N2 as T2) -- 16 rows
 ,N4(C) as (select 0 from N3 as T1 cross join N3 as T2) -- 256 rows
 ,N5(C) as (select 0 from N4 as T1 cross join N4 as T2) -- 65,536 rows
 ,IDs(ID) as (select row_number() over (order by (select null)) from N5)
 insert into dbo.UniqueidentifierCI(Val)
     select ID from IDs; 

select page_count, avg_page_space_used_in_percent, avg_fragmentation_in_percent
 from sys.dm_db_index_physical_stats(db_id(),object_id(N‘dbo.IdentityCI‘),1,null,‘DETAILED‘); 

select page_count, avg_page_space_used_in_percent, avg_fragmentation_in_percent
 from  sys.dm_db_index_physical_stats(db_id(),object_id(N‘dbo.UniqueidentifierCI‘),1,null ,‘DETAILED‘); 

图7-4.  索引碎片

如您所见,uniqueidentifier列上的索引严重碎片化,与标识列上的索引相比,它使用的数据页数大约多40%。 在uniqueidentifier列的索引中的批量插入会在数据文件的不同位置插入数据,这会导致在大型表的情况下出现繁重的随机物理I / O. 这可能会显着降低操作性能。

个人经验

前段时间,我参与了一个系统的优化,该系统具有250 GB的表,其中包含一个聚簇索引和三个非聚簇索引。 其中一个非聚集索引就是索引 uniqueidentifier列。 通过删除此索引,我们能够将50,000行的批量插入从45秒加速到7秒。

当您想要在uniqueidentifier列上创建索引时,有两种常见用例。第一个是支持跨多个数据库的值的唯一性。想想可以将行插入每个数据库的分布式系统。开发人员经常使用uniqueidentifiers来确保每个键值在系统范围内都是唯一的。此类实现中的关键元素是如何生成键值。

正如您已经看到的,使用NEWID()函数或客户端代码生成的随机值会对系统性能产生负面影响。但是,您可以使用NEWSEQUENTIALID()函数,该函数生成唯一且通常不断增加的值(SQL Server会不时重置其基值)。使用NEWSEQUENTIALID()函数生成的uniqueidentifier列的索引类似于identity和sequence列的索引;但是,您应该记住,uniqueidentifier数据类型使用16字节的存储空间,而4字节的int或8字节的bigint数据类型。

作为替代解决方案,您可以考虑创建具有两列的复合索引(InstallationId,Unique_Id_Within_Installation)。这两列的组合保证了多个安装和数据库的唯一性,并且比独特标识符使用更少的存储空间。您可以使用整数标识或序列来生成Unique_Id_Within_Installation值,这将减少索引的碎片。

如果需要在数据库中的所有实体上生成唯一键值,则可以考虑在所有实体中使用单个序列对象。此方法满足要求,但使用比uniqueidentifier更小的数据类型。

另一个常见用例是安全性,其中uniqueidentifier值用作安全性令牌或随机对象ID。不幸的是,您无法在此方案中使用NEWSEQUENTIALID()函数,因为可以猜测该函数返回的下一个值。

在这种情况下,一种可能的改进是使用CHECKSUM()函数创建计算列,然后对其进行索引,而不在uniqueidentifier列上创建索引。代码如清单7-6所示。

清单7-6. 使用CHECKSUM():表结构

create table dbo.Articles
 (
     ArticleId int not null identity(1,1),
     ExternalId uniqueidentifier not null
         constraint DEF_Articles_ExternalId
         default newid(),
     ExternalIdCheckSum as checksum(ExternalId),
     /* Other Columns */
 ); 

create unique clustered index IDX_Articles_ArticleId
 on dbo.Articles(ArticleId); 

create nonclustered index IDX_Articles_ExternalIdCheckSum
 on dbo.Articles(ExternalIdCheckSum); 

■ 提示:您可以索引计算列而不保留它。

尽管IDX_Articles_ExternalIdCheckSum索引将严重分段,但与uniqueidentifier列上的索引(4字节密钥与16字节)相比,它将更紧凑。 它还提高了批处理操作的性能,因为更快的排序,这也需要更少的内存来进行。

你必须记住的一件事是CHECKSUM()函数的结果不保证是唯一的。 您应该在查询中包含两个谓词,如清单7-7所示。

清单7-7. 使用CHECKSUM():选择数据

select ArticleId /* Other Columns */
from dbo.Articles
where checksum(@ExternalId) = ExternalIdCheckSum and ExternalId = @ExternalId 

■ 提示:如果需要索引大于900 / 1,700字节的字符串列(这是非聚集索引键的最大大小),则可以使用相同的技术。 即使这样的索引不支持范围扫描操作,它也可以用于点查找。

原文地址:https://www.cnblogs.com/ZQHHP/p/10093239.html

时间: 2024-10-12 20:24:16

翻译: Clustered Index Design Considerations 聚集索引设计注意事项的相关文章

《Pro SQL Server Internals, 2nd edition》中CHAPTER 7 Designing and Tuning the Indexes中的Clustered Index Design Considerations一节(译)

<Pro SQL Server Internals> 作者: Dmitri Korotkevitch 出版社: Apress出版年: 2016-12-29页数: 804定价: USD 59.99装帧: PaperbackISBN: 9781484219638 索引的设计与调整 索引不可能在任何地方都适用.每个系统都是独特的,并且需要基于工作负载.业务需求和许多其他因素的自己的索引方法.然而,有几个设计考虑和指导方针可以应用在每个系统中. 当我们优化现有系统时也是如此.虽然优化是一个迭代过程,在

非聚集索引的注意事项

1.在非聚集索引中包含了对聚集索引的引用.也就是说在非聚集索引页上面保存了聚集索引的一份数据2.当查询包含非聚集索引列的数据时,首先对非聚集索引进行扫描,然后通过非聚集索引找到聚集索引,最后通过聚集索引定位数据3.如果select中包含非聚集索引列(A)和非索引列(B),当通过条件A(Where A)查询B列(Select B)时,过程如下,通过A找到对应的聚集索引Id,在通过ID 定位到磁盘上面的那一行数据,最后读取那一行数据的B列.(操作较复杂,可将B列也包含到非聚集索引中,就不用走这么多流

索引 - 非聚集索引设计指南-转载

非聚集索引包含索引键值和指向表数据存储位置的行定位器. 有关非聚集索引体系结构的详细信息, 请参阅 非聚集索引结构. 可以对表或索引视图创建多个非聚集索引. 通常, 设计非聚集索引是为改善经常使用的没有建立聚集索引的查询的性能. 与使用书中索引的方式相似, 查询优化器在搜索数据值时, 先搜索非聚集索引以找到数据值在表中的位置, 然后直接从该位置检索数据. 这使非聚集索引成为完全匹配查询的最佳选择, 因为索引包含说明查询所搜索的数据值在表中的精确位置的项. 例如, 为了从 Person.Perso

索引 - 聚集索引设计指南-转载

聚集索引基于数据行的键值在表内排序和存储这些数据行, 每个表只能有一个聚集索引, 因为数据行本身只能按一个顺序存储. 有关聚集索引体系结构的详细信息, 请参阅 聚集索引结构. 每个表几乎都对列定义聚集索引来实现下列功能: 可用于经常使用的查询. 提供高度唯一性. 创建 PRIMARY KEY 约束时, 将在列上自动创建唯一索引. 默认情况下, 此索引是聚集索引, 但是在创建约束时,可以指定创建非聚集索引. 可用于范围查询. 如果未使用 UNIQUE 属性创建聚集索引, 数据库引擎将向表自动添加一

SQL存储原理及聚集索引、非聚集索引、唯一索引、主键约束的关系(补)

索引类型 1.          唯一索引:唯一索引不允许两行具有相同的索引值 2.          主键索引:为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型.主键索引要求主键中的每个值是唯一的,并且不能为空 3.          聚集索引(Clustered):表中各行的物理顺序与键值的逻辑(索引)顺序相同,每个表只能有一个 4.          非聚集索引(Non-clustered):非聚集索引指定表的逻辑顺序.数据存储在一个位置,索引存储在另一个位置,索引中包含指

Clustered Index Scan 与 Clustered Index Seek

Clustered Index Scan 与 Clustered Index Seek 在利用 SQL Server 查询分析器的执行计划中,会有许多扫描方式,其中就有 Clustered Index Scan 与 Clustered Index Seek,这二者有什么区别呢? Clustered Index,为聚集索引,表示它们使用的都是聚集索引扫描. Scan 表示它扫描一个范围或者是全部内容,Seek 表示扫描特定范围内的行.也就是说 Scan 并不知道要目标行是哪些,而 Seek 扫描表

slqserver 主键自动添加聚集索引的问题

据我们所了解,sqlserver 在添加主键的时候,会自动将我宝贵的聚集索引添加在我们的ID 上,然后,有些时候,我们想添加在 常用的搜索的字段上,这个时候,如果主键已经创建了:我们可以使用下面的方法来进行更改: --create index index_索引名 on 表名(列名) sp_helpindex 'Category' --查看表的索引 exec sp_helpconstraint 'Category' --查看表的约束 Alter Table Category DROP constr

sqlserver聚合索引(clustered index) / 非聚合索引(nonclustered index)的理解

1. 什么是聚合索引(clustered index) / 什么是非聚合索引(nonclustered index)? 可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonclustered index,也称非聚类索引.非簇集索引).下面,我们举例来说明一下聚集索引和非聚集索引的区别: 其实,我们的汉语字典的正文本身就是一个聚集索引.比如,我们要查"安"字,就会很自然地翻开字典的

聚合索引(clustered index) / 非聚合索引(nonclustered index)

以下我面试经常问的2道题..尤其针对觉得自己SQL SERVER 还不错的同志.. 呵呵 很难有人答得好.. 各位在我收集每个人擅长的东西时,大部分都把SQL SERVER 标为Expert,看看是否答的上来.. 1. 什么是聚合索引(clustered index) / 什么是非聚合索引(nonclustered index)? 2. 聚合索引和非聚合索引有什么区别? 深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clust