我对DB的接触有限,只使用DB做为应用程序程序员。 我想了解Clustered
和Non clustered indexes
。 我搜索了一下,发现的是: 程序员
汇集索引是一种特殊的索引,它从新排序表中记录的物理存储方式。 所以,表只能有一个汇集索引。 汇集索引的叶节点包含数据页。 非汇集索引是一种特殊类型的索引,其中索引的逻辑顺序与磁盘上行的物理存储顺序不匹配。 非汇集索引的叶节点不包含数据页。 相反,叶节点包含索引行。 sql
我在SO中发现的是汇集索引和非汇集索引之间的区别是什么? 。 数据库
有人能够用简单的英语解释吗? 数组
汇集索引意味着您要告诉数据库在磁盘上存储实际上彼此接近的关闭值。 这具备快速扫描/检索落入汇集索引值范围内的记录的好处。 app
例如,您有两个表Customer和Order: dom
Customer ---------- ID Name Address Order ---------- ID CustomerID Price
若是但愿快速检索一个特定客户的全部订单,则可能但愿在“订单”表的“客户ID”列上建立聚簇索引。 这样,具备相同CustomerID的记录将在物理上彼此靠近存储在磁盘上(成簇),从而加快了检索速度。 ui
PS客户ID上的索引显然不是惟一的,所以您要么须要添加第二个字段来“统一”索引,要么让数据库为您处理该索引,但这是另外一回事了。 spa
关于多个索引。 每一个表只能有一个汇集索引,由于它定义了数据的物理排列方式。 若是您想打个比方,请想象一个有不少桌子的大房间。 您能够将这些表造成几行,也能够将它们所有拉在一块儿以造成一个大会议表,但不能同时使用两种方法。 一个表能够有其余索引,它们将指向汇集索引中的条目,而汇集索引又将最终说出在哪里能够找到实际数据。 指针
使用汇集索引时,行将以与索引相同的顺序物理存储在磁盘上。 所以,只能有一个聚簇索引。 code
使用非汇集索引时,第二个列表具备指向物理行的指针。 您能够有许多非汇集索引,尽管每一个新索引都会增长写入新记录所需的时间。
若是要取回全部列,一般从汇集索引中读取会更快。 您没必要先进入索引,而后再进入表。
若是须要从新排列数据,则写入具备汇集索引的表的速度可能会变慢。
一个很是简单的,非技术性的经验法则是,汇集索引一般用于主键(或至少是惟一列),而非汇集索引用于其余状况(也许是外键) 。 实际上,默认状况下,SQL Server将在您的主键列上建立聚簇索引。 正如您将学到的,汇集索引与磁盘上数据的物理排序方式有关,这意味着在大多数状况下,它是一个很好的全面选择。
在下面找到汇集索引和非汇集索引的一些特征:
create Index index_name(col1, col2, col.....)
。 在SQL Server面向行的存储中,汇集索引和非汇集索引都组织为B树。
( 图片来源 )
汇集索引和非汇集索引之间的主要区别在于,汇集索引的叶级是表。 这有两个含义。
非汇集索引也能够经过使用INCLUDE
子句(自SQL Server 2005开始)明确包含全部非键列来进行第1点的操做,可是它们是辅助表示,而且周围始终有另外一个数据副本(表自己)。
CREATE TABLE T ( A INT, B INT, C INT, D INT ) CREATE UNIQUE CLUSTERED INDEX ci ON T(A,B) CREATE UNIQUE NONCLUSTERED INDEX nci ON T(A,B) INCLUDE (C,D)
上面的两个索引几乎相同。 上级索引页面包含键列A,B
值,叶级页面包含A,B,C,D
每一个表只能有一个汇集索引,由于数据行自己只能以一种顺序排序。
上面SQL Server在线丛书中的引用引发不少混乱
我认为最好用这样的措辞。
每一个表只能有一个汇集索引,由于汇集索引的叶级行是表行。
联机丛书的报价并不正确,可是您应该清楚非汇集索引和汇集索引的“排序”是逻辑上而非物理上的。 若是您经过遵循连接列表来读取叶级页面,并以插槽数组顺序读取页面上的行,则您将以排序的顺序读取索引行,但实际上页面可能未排序。 一般认为,使用汇集索引时,行老是以与索引键相同的顺序物理存储在磁盘上,这是错误的。
这将是荒谬的实现。 例如,若是某行插入到4GB桌子中间的SQL Server 没有在文件中的数据拷贝2GB高达腾出空间给新插入的行。
而是发生页面拆分。 聚簇索引和非聚簇索引的叶级上的每一个页面都有按逻辑键顺序排列的下一页和上一页的地址( File:Page
)。 这些页面没必要是连续的或按键顺序排列的。
例如,连接的页面链多是1:2000 <-> 1:157 <-> 1:7053
当发生页面拆分时,将从文件组中的任何位置分配新页面(从混合范围(对于小型表),或者属于该对象的非空统一范围或新分配的统一范围)。 若是文件组包含多个文件,则该文件甚至可能不在同一文件中。
逻辑顺序和连续性与理想物理版本不一样的程度是逻辑碎片的程度。
在一个只有一个文件的新建立的数据库中,我运行了如下命令。
CREATE TABLE T ( X TINYINT NOT NULL, Y CHAR(3000) NULL ); CREATE CLUSTERED INDEX ix ON T(X); GO --Insert 100 rows with values 1 - 100 in random order DECLARE @C1 AS CURSOR, @X AS INT SET @C1 = CURSOR FAST_FORWARD FOR SELECT number FROM master..spt_values WHERE type = 'P' AND number BETWEEN 1 AND 100 ORDER BY CRYPT_GEN_RANDOM(4) OPEN @C1; FETCH NEXT FROM @C1 INTO @X; WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO T (X) VALUES (@X); FETCH NEXT FROM @C1 INTO @X; END
而后使用
SELECT page_id, X, geometry::Point(page_id, X, 0).STBuffer(1) FROM T CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% ) ORDER BY page_id
结果处处都是。 按键顺序的第一行(值1-用下面的箭头突出显示)几乎在最后一个物理页面上。
经过重建或从新组织索引以增长逻辑顺序和物理顺序之间的相关性,能够减小或消除碎片。
跑步后
ALTER INDEX ix ON T REBUILD;
我获得如下
若是表没有聚簇索引,则称为堆。
非汇集索引能够创建在堆索引或汇集索引上。 它们始终包含返回到基表的行定位器。 对于堆,这是物理行标识符(rid),由三个组件(File:Page:Slot)组成。 对于聚簇索引,行定位符是逻辑的(聚簇索引键)。
对于后一种状况,若是非聚簇索引已经天然地包括CI键列(做为NCI键列或INCLUDE
-d列),则不添加任何内容。 不然,缺乏的CI键列将被静默添加到NCI中。
SQL Server始终确保两种索引类型的键列都是惟一的。 可是,对于未声明为惟一的索引,强制执行此机制的机制在两种索引类型之间有所不一样。
聚簇索引会为具备重复现有行的键值的任何行添加一个uniquifier
。 这只是一个递增的整数。
对于未声明为惟一的非汇集索引,SQL Server会将行定位符静默添加到非汇集索引键中。 这适用于全部行,而不只仅是实际重复的行。
聚类命名法与非聚类命名法也用于列存储索引。 本文对SQL Server列存储的加强状态
尽管列存储数据并无真正“汇集”在任何键上,但咱们仍是决定保留传统的SQL Server约定,即将主索引称为聚簇索引。