SqlServer聚集索引原理
测试所用数据库:SQLSERVER2012
我们都知道索引能提高查询速度,那么索引到底是怎么提高查询速度的呢?这要从索引的数据结构说起
索引分为聚集索引和非聚集索引,这两种索引的数据结构都是B+树,这篇文章主要讲解聚集索引
首先我们创建一个测试表:
CREATE TABLE Department(DepartmentID int IDENTITY(1,1) NOT NULL PRIMARY KEY,Name NVARCHAR(200) NOT NULL,GroupName NVARCHAR(200) NOT NULL,Company NVARCHAR(300),ModifiedDate datetime NOT NULL DEFAULT (getdate()))
再创建一个用来存储表对象内部存储信息的表:
CREATE TABLE DBCCResult (PageFID NVARCHAR(200),PagePID NVARCHAR(200),IAMFID NVARCHAR(200),IAMPID NVARCHAR(200),ObjectID NVARCHAR(200),IndexID NVARCHAR(200),PartitionNumber NVARCHAR(200),PartitionID NVARCHAR(200),iam_chain_type NVARCHAR(200),PageType NVARCHAR(200),IndexLevel NVARCHAR(200),NextPageFID NVARCHAR(200),NextPagePID NVARCHAR(200),PrevPageFID NVARCHAR(200),PrevPagePID NVARCHAR(200))
向表Department中插入测试数据
INSERT INTO Department(name,[Company],groupname) VALUES('销售部','中国你好有限公司XX分公司','销售组')GO 100000
将表Department的内部存储信息写入到表DBCCResult中:
INSERT INTO DBCCResult EXEC ('DBCC IND(indextest,Department,-1) ')
DBCC ind:查询 indextest数据库中Department表的内部存储信息。然后将查询结果插入到表DBCCResult,关于DBCC IND的详细用法请参考MSDN.
查询表DBCCResult的内容:
PageType 分页类型: 1:数据页面;2:索引页面;3:Lob_mixed_page;4:Lob_tree_page;10:IAM页面
IndexID 索引ID: 0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 ,大于250就是text或image字段
IndexLevel 索引层次:0代表叶子节点,1代表叶子节点的上一层节点,以此类推,最大的那个数即是树的高度
为了更突出树的结构,我们查询索引页面:
select * from DBCCResult where PageType<>1
1、第一条数据PageType=10,表示这是一个IAM页面,IAM页不是只有堆表才有也不只是维护堆表中的数据页的连续,有索引的表都有,所以IAM页不只维护数据页,也维护索引页的连续
2、下面三条数据的PageType=2,表示索引页面。第3条数据的IndexLevel=2,表示这是根节点,第2条和第4条是它的子节点
3、每个数据页的IndexID都是1,不是说数据页变成了索引页,而是说现在数据页已经属于聚集索引的一部分,不在堆里了
4、每个数据页的IndexLevel都是0,就是说数据页在聚集索引的最下层。IndexID=1并且PageType=1的IndexLevel=0,这个表示聚集索引的叶子节点就是数据页。
下面我们来看一下索引页里的内容:
首先我们打开3604跟踪标志,将dbcc的输出返回到客户端;
dbcc traceon(3601,-1)
查询索引页面的页面信息:
dbcc page('IndexTest',1,943,3)dbcc page('IndexTest',1,121,3)dbcc page('IndexTest',1,944,3)
我的根页面的PageId是943,大家可查看自己的根页面ID是多少,替换943查询
我们可以看到DepartmentID后面有一个key,表明这是一个索引列,这个值就是DepartmentID的值。还有两个列需要特别注意:ChildPageId和KeyHashValue。一个非叶级节点有3部分组成:主键值(DepartmentID)、指向下一个节点的指针(ChildPageId)、主键值的哈希值。但是目前我们的主键哈希值为空,这一点我现在也没弄明白。
我们可以看到每个部门ID和下一行的部门ID都相差了120条记录,这说明一个数据页只能容纳120条记录
使用聚集索引查找数据有2种方式:聚集索引查找和聚集索引扫描
聚集索引查找流程:先用二分法找到实际的数据页面,然后再从数据页面中把数据读出来。
需要特别注意的是:聚集索引查询并不能具体定位到某一条记录,而是定位到数据页,即PageID。数据库会把所有的数据页都加载到内存中,在内存中的一个数据页中查找一条记录,这个是很快的,几乎可以忽略不记。
对于聚集索引扫描,我们举个例子来看一下:
创建一个新的Department3表:
CREATE TABLE Department3(DepartmentID int IDENTITY(1,1) NOT NULL PRIMARY KEY,Name NVARCHAR(200) NOT NULL,GroupName NVARCHAR(200) NOT NULL,Company NVARCHAR(300),ModifiedDate datetime NOT NULL DEFAULT (getdate()))
插入测试数据:
DECLARE @i INT
SET @i=1
WHILE @i <= 100000
BEGININSERT INTO Department3 ( name, [Company], groupname )VALUES ( '销售部', '中国你好有限公司XX分公司'+CAST(@i AS VARCHAR(200)), '销售组'+CAST(@i AS VARCHAR(200)) )SET @i = @i + 1
END
使用隔离级别为可重复读的事务读取数据,这个操作的目的是查看数据库锁的使用情况
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
begin tranSELECT * FROM [dbo].[Department3] WHERE [GroupName] ='销售组83421'SELECT[request_session_id],c.[program_name],DB_NAME(c.[dbid]) AS dbname,[resource_type],[request_status],[request_mode],[resource_description],OBJECT_NAME(p.[object_id]) AS objectname,p.[index_id]FROM sys.[dm_tran_locks] AS a LEFT JOIN sys.[partitions] AS pON a.[resource_associated_entity_id]=p.[hobt_id]LEFT JOIN sys.[sysprocesses] AS c ON a.[request_session_id]=c.[spid]WHERE c.[dbid]=DB_ID('indextest') and OBJECT_NAME(p.[object_id])='Department3'ORDER BY [resource_type]
commit tran
结果如下:
可以看到查询使用的聚集索引扫描。关于锁,我们看[resource_type]字段,有一个key(键锁)和大量的Page(页锁)。那这是为什么呢?因为聚集索引的数据页就是索引页,位于B+树的最底层。所以要扫描表里面的数据,即是扫描整个聚集索引。所以聚集索引扫描和整表扫描耗时是没有多大区别的。
加键锁是因为定位到那一条数据后,需要在记录所在的数据页上加一个键锁,防止其他人篡改。
因为聚集索引扫描等同于整表扫描,SQLSERVER要不停地扫描所有的数据页,所以所有的数据页都加上了页锁。
总结:
1、SQLSERVER索引采用B+树数据结构存储
2、聚集索引的数据页即是聚集索引的叶子节点,也就是说有聚集索引的表,表中的所有列的数据都存储在叶子节点中。索引页只起到导航的作用,每次查询都要查询到叶子节点为止。
3、叶子节点的每个相邻节点都有2个指针,一个指向前一个节点,一个指向下一个节点,按照键值从左到右排序,组成了一个有序的链表。排序的规则是按照聚集索引的第一列排序。
4、聚集索引查找并不能定位到数据页中的某一条记录,而是定位到某一个数据页,然后在数据页中查询。
SqlServer聚集索引原理相关推荐
- Sqlserver 高级篇 聚集索引原理
原理 Sqlserver 高级篇 非聚集索引原理 说完非聚集索引 接着说 聚集索引 聚集索引就是把数据按照 用户设置排好顺序 与非聚集索引不同 非聚集索引不会动数据页 只会新增一个索引表 聚集索引直 ...
- SQLSERVER聚集索引与非聚集索引的再次研究(下)
上篇主要说了聚集索引和简单介绍了一下非聚集索引,相信大家一定对聚集索引和非聚集索引开始有一点了解了. 这篇文章只是作为参考,里面的观点不一定正确 上篇的地址:SQLSERVER聚集索引与非聚集索引的再 ...
- SQLSERVER聚集索引的整理(重建)的必要性测试
SQLSERVER 在日常DBA工作中有一项叫索引整理 一般整理的多为非聚集索引 问题:聚集索引是否需要整理?在什么情况下需要整理?整理的效果如何?有没有负面作用? 测试环境:WIN2003+SQL2 ...
- sqlserver聚集索引和非聚集索引并存
前面两篇文章讲解了一个数据表只存在聚集索引和只存在非聚集索引的情况,接下来我们来讨论一下当聚集索引和非聚集索引同时存在的情况,这种情况也是大多数表都存在的情况. CREATE TABLE Depart ...
- sql server 创建唯一性非聚集索引语句_数据库专题—索引原理
深入浅出数据库索引原理 参见:https://www.cnblogs.com/aspwebchh/p/6652855.html 1.为什么给表加上主键? 1.平时创建表的时候,都会给表加上主键.如果没 ...
- SqlServer为什么自动在主键上建立聚集索引
微软推荐为每一个表建立一个聚集索引,但是由于sqlserver简单易用,而且很多人并不了解聚集索引,非聚集索引这些东西,所以如果sqlserver不在主键上建立聚集索引的话,可能会导致大部分的表都是堆 ...
- 一篇读懂聚集索引、非聚集索引、覆盖索引的工作原理!
作者:PostTruth 「数据库」和「数据库索引」这两个东西是在服务器端开发领域应用最为广泛的两个概念,熟练使用数据库和数据库索引是开发人员在行业内生存的必备技能. 使用索引很简单,只要能写创建表的 ...
- SQLServer之创建非聚集索引
开始之前 典型实现 可以通过下列方法实现非聚集索引: UNIQUE 约束 在创建 UNIQUE 约束时,默认情况下将创建唯一非聚集索引,以便强制 UNIQUE 约束. 如果不存在该表的聚集索引,则可以 ...
- mysql索引 聚集索引_Mysql 索引实现原理. 聚集索引, 非聚集索引
Mysql索引实现: B-tree,B是balance,一般用于数据库的索引.使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度.而B+tree是B-tree的一个变种,My ...
最新文章
- 单调队列多重背包时间复杂度O(vn)
- c语言编的游戏怎么在安卓平台使用,谁知道怎么把c语言写的游戏安装到安卓手机上面玩??...
- Python忽略Warning输出
- LeetCode-剑指 Offer 25. 合并两个排序的链表
- JMeter入门案例
- SpringBoot_配置-配置文件占位符
- 小程序 报错errMsg: “hideLoading:fail:toast can‘t be found“ ?
- 浅谈ARMv8-A系列CPU的架构
- python import _ssl_如何在python 2.7.6中导入_ssl?
- 循序渐进学.Net Core Web Api开发系列【7】:项目发布到CentOS7
- webserver入门
- spring boot部署实战
- 正则表达式的学习使用
- maven的Lifecycle生命周期
- kill mysql 进程_如何快速处理mysql连接数占满的问题?
- 【Oozie】CDH集群的oozie手把手快速入门
- BT.1120数据流解释
- (已实现)Mysql实现模糊拼音查询(Mybatis可直接使用)
- win10计算机管理权限,win10如何获取管理员权限?win10获取最高权限的方法
- C++ 167. 两数之和 II 633. 平方数之和
热门文章
- 联邦学习安全之攻防简介
- 华为超级计算机,华为超级计算机打破世界纪录,是否超越了我国第一的“神威太湖之光”?...
- 微服务中使用 OpenJ9 JVM 内存占用降60%(相对HotSpot)
- 【MinIO】MinIO分布式部署
- lintcode 949. 斐波那契数列 II
- 工作的记录,hibernate的evict,load使用
- Android logcat log丢失
- uniapp侧边导航栏大概思路
- 高通量测序分析工具Bedtools使用介绍
- 如何关闭QQ网购每日精选信息提醒