SQL Server如何在变长列上存储索引

原文:SQL Server如何在变长列上存储索引

这篇文章我想谈下SQL Server如何在变长列上存储索引。首先我们创建一个包含变长列的表,在上面定义主键,即在上面定义了聚集索引,然后往里面插入80000条记录:

 1 -- Create a new table
 2 CREATE TABLE Customers
 3 (
 4     CustomerName VARCHAR(255) NOT NULL PRIMARY KEY,
 5     Filler CHAR(138) NOT NULL
 6 )
 7 GO
 8
 9 -- Insert 80.000 records
10 DECLARE @i INT = 1
11 WHILE (@i <= 80000)
12 BEGIN
13     INSERT INTO Customers VALUES
14     (
15         'CustomerName' + CAST(@i AS VARCHAR),
16         'Filler' + CAST(@i AS VARCHAR)
17     )
18
19     SET @i += 1
20 END
21 GO

从代码里我们可以看到,我在VARCHAR(255)列上建立了主键约束,SQL Server会强制这列为唯一聚集索引。接下来我们通过DMV sys.dm_db_index_physical_stats来获取聚集索引的相关物理信息: 

 1 -- Retrieve physical information about the clustered index
 2 SELECT * FROM sys.dm_db_index_physical_stats
 3 (
 4     DB_ID('ALLOCATIONDB'),
 5     OBJECT_ID('Customers'),
 6     NULL,
 7     NULL,
 8     'DETAILED'
 9 )
10 GO

从输出结果可以看出,在索引页里,min_record_size_in_bytes列的值是7,max_record_size_in_bytes列的值是28。我们据此可以得出结论:在索引记录内部,聚集键是以变长列保存的。我们建立一个帮助表来存储DBCC IND的输出信息来做进一步分析。

 

 1 -- Create a helper table
 2 CREATE TABLE HelperTable
 3 (
 4   PageFID TINYINT,
 5   PagePID INT,
 6   IAMFID TINYINT,
 7   IAMPID INT,
 8   ObjectID INT,
 9   IndexID TINYINT,
10   PartitionNumber TINYINT,
11   PartitionID BIGINT,
12   iam_chain_type VARCHAR(30),
13   PageType TINYINT,
14   IndexLevel TINYINT,
15   NextPageFID TINYINT,
16   NextPagePID INT,
17   PrevPageFID INT,
18   PrevPagePID INT,
19   PRIMARY KEY (PageFID, PagePID)
20 )
21 GO
22
23 -- Write everything in a table for further analysis
24 INSERT INTO HelperTable EXEC('DBCC IND(ALLOCATIONDB, Customers, 1)')
25 GO
26
27 -- Retrieve the root index page (1 page)
28 SELECT * FROM HelperTable
29 WHERE IndexLevel = 2
30 GO

我这里的根页是15058,我们使用DBCC PAGE命令查看下这个根页(记得先执行 DBCC TRACEON(3604))。

1 DBCC TRACEON (3604)
2 GO
3 --Dump out the root index page
4 DBCC PAGE(ALLOCATIONDB, 1, 15058, 1)
5 GO

即如下所示的数字:

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。在设计索引和计算一个索引页存放多少索引记录时,要留意这些存储开销。

时间: 2024-07-30 10:16:19

SQL Server如何在变长列上存储索引的相关文章

浅析SQL Server中的执行计划缓存(上)_MsSql

简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询优化(Optimization,有时候也被称为简化).执行(Execution).除去执行步骤外,前三个步骤之后就生成了执行计划,也就是SQL Server按照该计划获取物理数据方式,最后执行步骤按照执行计划执行查询从而获得结果.但查询优化器不是本篇的重点,本篇文章主要讲述查询优化器在生成执行计划之

浅析SQL Server中的执行计划缓存(上)

简介 我们平时所写的SQL语句本质只是获取数据的逻辑,而不是获取数据的物理路径.当我们写的SQL语句传到SQL Server的时候,查询分析器会将语句依次进行解析(Parse).绑定(Bind).查询优化(Optimization,有时候也被称为简化).执行(Execution).除去执行步骤外,前三个步骤之后就生成了执行计划,也就是SQL Server按照该计划获取物理数据方式,最后执行步骤按照执行计划执行查询从而获得结果.但查询优化器不是本篇的重点,本篇文章主要讲述查询优化器在生成执行计划之

浅析SQL Server数据库中的伪列以及伪列的含义

原文:浅析SQL Server数据库中的伪列以及伪列的含义   本文出处:http://www.cnblogs.com/wy123/p/6833116.html      SQL Server中的伪列 下午看QQ群有人在讨论(非聚集)索引的存储,说,对于聚集索引表,非聚集索引存储的是索引键值+聚集索引键值:对于非聚集索引表,索引存储的是索引键值+RowId,这应该是一个常识,对此不作具体详细阐述.这里主要是提到的RowId引起了一点思考.那么,这个RowId是个什么玩意?能不能更加直观一点来看看

Sql Server 性能优化之包含列

原文:Sql Server 性能优化之包含列 Sql Server 性能优化之包含列        导读:数据数优化查询一直是个比较热门的话题,小生在这方面也只能算是个入门生.今 天我们就讲下数据库包含列这个一项的作用及带来的优化效果           引用下MSDN里面的一段解释:        当查询中的所有列都作为键列或非键列包含在索引中时,带有包含性非键列的索引可以显 著提高查询性能. 这样可以实现性能提升,因为查询优化器可以在索引中找到所有列值:不 访问表或聚集索引数据,从而减少磁盘

SQL Server表中添加新列并添加描述_MsSql

注: sql server 2005 及以上支持. 版本估计是不支持(工作环境2005,2008). 工作需要, 需要向SQL Server 现有表中添加新列并添加描述. 从而有个如下存储过程. (先附上存储过程然后解释) /********调用方法********** 作用: 添加列并添加列描述信息 调用: exec [SetColumnInfo] '表名', '列名', N'列说明,描述','列类型{默认:NVARCHAR(50)}','列默认值{默认:NULL}' ************

SQL Server表中添加新列并添加描述

注: sql server 2005 及以上支持. 版本估计是不支持(工作环境2005,2008). 工作需要, 需要向SQL Server 现有表中添加新列并添加描述. 从而有个如下存储过程. (先附上存储过程然后解释) /********调用方法********** 作用: 添加列并添加列描述信息 调用: exec [SetColumnInfo] '表名', '列名', N'列说明,描述','列类型{默认:NVARCHAR(50)}','列默认值{默认:NULL}' ************

Sql Server中判断表、列不存在则创建的方法

一.Sql Server中如何判断表中某列是否存在 首先跟大家分享Sql Server中判断表中某列是否存在的两个方法,方法示例如下: 比如说要判断表A中的字段C是否存在两个方法: 第一种方法 IF EXISTS ( SELECT 1 FROM SYSOBJECTS T1 INNER JOIN SYSCOLUMNS T2 ON T1.ID=T2.ID WHERE T1.NAME='A' AND T2.NAME='C' ) PRINT '存在' ELSE PRINT '不存在' 第二种方法,短小精

SQL SERVER中什么情况会导致索引查找变成索引扫描

SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方面结合上下文具体场景做了下测试.总结.归纳.   1:隐式转换会导致执行计划从索引查找(Index Seek)变为索引扫描(Index Scan) Implicit Conversion will cause index scan instead of index seek. While implicit conversions occur in SQL Ser

SQL Server查询性能优化之创建合理的索引(下)

续上一篇SQLServer查询性能优化之创建合理的索引(上) 数据库索引分为聚集索引和非聚集索引,聚集索引就是物理索引,也就是数据的物理的存储顺序,聚集索引的叶子节点就是数据行本身:非聚集索引是逻辑索引,也可以简单的认为是对聚集索引建立的索引,一般来说聚集索引的键就是非聚集索引的叶子节点(在不使用include时). 关于索引的选择 对于索引类型来说没什么好选的,一般来说聚集索引是必须的(有特殊需要的另说),非聚集索引看实际需要灵活建立.因此对于索引来说主要是决定在那些列上建立索引,尤其是对于聚