SQL Server如何在变长列上存储索引
2015-06-15 11:49
561 查看
原文:SQL Server如何在变长列上存储索引这篇文章我想谈下SQL Server如何在变长列上存储索引。首先我们创建一个包含变长列的表,在上面定义主键,即在上面定义了聚集索引,然后往里面插入80000条记录:
从代码里我们可以看到,我在VARCHAR(255)列上建立了主键约束,SQL Server会强制这列为唯一聚集索引。接下来我们通过DMV sys.dm_db_index_physical_stats来获取聚集索引的相关物理信息:
![](http://images0.cnblogs.com/blog2015/750348/201506/151024272959162.png)
从输出结果可以看出,在索引页里,min_record_size_in_bytes列的值是7,max_record_size_in_bytes列的值是28。我们据此可以得出结论:在索引记录内部,聚集键是以变长列保存的。我们建立一个帮助表来存储DBCC IND的输出信息来做进一步分析。
![](http://images0.cnblogs.com/blog2015/750348/201506/151055199825455.png)
我这里的根页是15058,我们使用DBCC PAGE命令查看下这个根页(记得先执行 DBCC TRACEON(3604))。
![](http://images0.cnblogs.com/blog2015/750348/201506/151059216387361.png)
即如下所示的数字:
我们来分析下这些16进制值:
26 95020000 0100 0100 1b00 43757374 6f6d6572 4e616d65 31333533
26 第1个字节代表状态位
95020000 这4个字节代表索引记录指向的子页id(child-page-id)
0100 这2个字节代表索引记录指向的子文件id(child-file-id)
0100 这2个字节代表变长列数
1b00 这2个字节代表每个变长列结束为止的偏移量。每个变长列需要2字节。这个和在数据页里存储变长列一致。这里我们有1个变长列,因此SQL Server需要1个 2 byte的偏移量——27 byte的偏移量。这就是说下一个字节一直到27 byte的偏移量都是我们变长列(聚集键)的组成部分。
43757374 6f6d6572 4e616d65 31333533 聚集键的16进制值,即CustomerName列。
从上面的解释,我们可以看出SQL Server存储变长索引列格式和数据页里存储变长列格式是一样的。但你要知道有一点额外开销,因为你需要额外2 bytes 来存储变长列个数,对于每个变长列在变长列偏移数组里需要2 bytes。在设计索引和计算一个索引页存放多少索引记录时,要留意这些存储开销。
-- Create a new table CREATE TABLE Customers ( CustomerName VARCHAR(255) NOT NULL PRIMARY KEY, Filler CHAR(138) NOT NULL ) GO -- Insert 80.000 records DECLARE @i INT = 1 WHILE (@i <= 80000) BEGIN INSERT INTO Customers VALUES ( 'CustomerName' + CAST(@i AS VARCHAR), 'Filler' + CAST(@i AS VARCHAR) ) SET @i += 1 END GO
从代码里我们可以看到,我在VARCHAR(255)列上建立了主键约束,SQL Server会强制这列为唯一聚集索引。接下来我们通过DMV sys.dm_db_index_physical_stats来获取聚集索引的相关物理信息:
-- Retrieve physical information about the clustered index SELECT * FROM sys.dm_db_index_physical_stats ( DB_ID('ALLOCATIONDB'), OBJECT_ID('Customers'), NULL, NULL, 'DETAILED' ) GO
![](http://images0.cnblogs.com/blog2015/750348/201506/151024272959162.png)
从输出结果可以看出,在索引页里,min_record_size_in_bytes列的值是7,max_record_size_in_bytes列的值是28。我们据此可以得出结论:在索引记录内部,聚集键是以变长列保存的。我们建立一个帮助表来存储DBCC IND的输出信息来做进一步分析。
-- Create a helper table CREATE TABLE HelperTable ( PageFID TINYINT, PagePID INT, IAMFID TINYINT, IAMPID INT, ObjectID INT, IndexID TINYINT, PartitionNumber TINYINT, PartitionID BIGINT, iam_chain_type VARCHAR(30), PageType TINYINT, IndexLevel TINYINT, NextPageFID TINYINT, NextPagePID INT, PrevPageFID INT, PrevPagePID INT, PRIMARY KEY (PageFID, PagePID) ) GO -- Write everything in a table for further analysis INSERT INTO HelperTable EXEC('DBCC IND(ALLOCATIONDB, Customers, 1)') GO -- Retrieve the root index page (1 page) SELECT * FROM HelperTable WHERE IndexLevel = 2 GO
![](http://images0.cnblogs.com/blog2015/750348/201506/151055199825455.png)
我这里的根页是15058,我们使用DBCC PAGE命令查看下这个根页(记得先执行 DBCC TRACEON(3604))。
DBCC TRACEON (3604) GO --Dump out the root index page DBCC PAGE(ALLOCATIONDB, 1, 15058, 1) GO
![](http://images0.cnblogs.com/blog2015/750348/201506/151059216387361.png)
即如下所示的数字:
00000000: 269d3b00 00010001 001b0043 7573746f †&.;........Custo 00000010: 6d65724e 616d6531 333533†††††††††††††merName1353
我们来分析下这些16进制值:
26 95020000 0100 0100 1b00 43757374 6f6d6572 4e616d65 31333533
26 第1个字节代表状态位
95020000 这4个字节代表索引记录指向的子页id(child-page-id)
0100 这2个字节代表索引记录指向的子文件id(child-file-id)
0100 这2个字节代表变长列数
1b00 这2个字节代表每个变长列结束为止的偏移量。每个变长列需要2字节。这个和在数据页里存储变长列一致。这里我们有1个变长列,因此SQL Server需要1个 2 byte的偏移量——27 byte的偏移量。这就是说下一个字节一直到27 byte的偏移量都是我们变长列(聚集键)的组成部分。
43757374 6f6d6572 4e616d65 31333533 聚集键的16进制值,即CustomerName列。
从上面的解释,我们可以看出SQL Server存储变长索引列格式和数据页里存储变长列格式是一样的。但你要知道有一点额外开销,因为你需要额外2 bytes 来存储变长列个数,对于每个变长列在变长列偏移数组里需要2 bytes。在设计索引和计算一个索引页存放多少索引记录时,要留意这些存储开销。
相关文章推荐
- Oracle数据库创建表是有两
- 在Oracle 中使用CONNECT BY PRIOR START WITH 语句详解
- MongoDB复制集成员的重新同步
- 第一章:MongoDB for windows下载安装
- redis配置文件redis.conf的详细说明
- redis windows下的环境搭建
- SQL Server中收缩、清空和删除数据库文件及日志文件
- golang实现对mysql数据库的操作
- SQL Server如何在变长列上存储索引
- redis 学习笔记(5)-Spring与Jedis的集成
- redis 学习笔记(4)-HA高可用方案Sentinel配置
- redis 学习笔记(3)-master/slave(主/从模式)
- redis 学习笔记(2)-client端示例代码
- redis 基本的了解
- redis 学习笔记(1)-编译、启动、停止
- mysql 获取今年至今的按照周聚集的统计
- mysql命令行操作
- 数据库事务隔离级别
- w3cschool.cc SQLite 教程
- 从运维角度浅谈 MySQL 数据库优化