原文来自:http://www.sqlskills.com/blogs/paul/mixed-pages-removed-index-rebuild/

在SQL SERVER 中,区是管理空间的基本单位,连续的8个页为一分区,分区可分为混合区和统一区(也叫独占区),混合区内存放一个或多个对象的数据,统一区只存放一个对象的数据。为提高空间的利用率,对于新表或索引,会先从混合区上分配页,当表或索引增长到 8 页时,将变成使用统一区进行后续分配。

让我们来测试下

首先,创建测试数据

  1. --====================================
  2. --创建测试表
  3. CREATE TABLE [MixedTest]
  4. (
  5. [c1] BIGINT IDENTITY ,
  6. [c2] CHAR(8000) DEFAULT 'a'
  7. );
  8. --=======================================
  9. --创建聚集索引
  10. CREATE CLUSTERED INDEX [MixedTest_CL]
  11. ON [MixedTest] ([c1]);
  12.  
  13. SET NOCOUNT ON;
  14. GO
  15. --====================================
  16. --插入1000条数据
  17. INSERT INTO [MixedTest]
  18. DEFAULT VALUES;
  19. GO 1000

Paul 使用sp_AllocationMetadata来查看对象的IAM页,然后再使用DBCC PAGE 查看IAM页的数据,从而判断数据页所在分区时混合还是统一区。

sp_AllocationMetadata的CODE:

  1. /*============================================================================
  2. File: sp_AllocationMetadata.sql
  3.  
  4. Summary: This script cracks the system tables to provide top-level
  5. metadata about a table or index
  6.  
  7. SQL Server Versions: 2005 onwards
  8. ------------------------------------------------------------------------------
  9. Written by Paul S. Randal, SQLskills.com
  10.  
  11. (c) 2014, SQLskills.com. All rights reserved.
  12.  
  13. For more scripts and sample code, check out
  14. http://www.SQLskills.com
  15.  
  16. You may alter this code for your own *non-commercial* purposes. You may
  17. republish altered code as long as you include this copyright and give due
  18. credit, but you must obtain prior permission before blogging this code.
  19.  
  20. THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  21. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  22. TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  23. PARTICULAR PURPOSE.
  24. ============================================================================*/
  25.  
  26. USE [master];
  27. GO
  28.  
  29. IF OBJECT_ID (N'sp_AllocationMetadata') IS NOT NULL
  30. DROP PROCEDURE [sp_AllocationMetadata];
  31. GO
  32.  
  33. CREATE PROCEDURE [sp_AllocationMetadata]
  34. (
  35. @object SYSNAME = NULL
  36. )
  37. AS
  38. SELECT
  39. OBJECT_NAME ([sp].[object_id]) AS [Object Name],
  40. [sp].[index_id] AS [Index ID],
  41. [sa].[allocation_unit_id] AS [Alloc Unit ID],
  42. [sa].[type_desc] AS [Alloc Unit Type],
  43. '(' + CONVERT (VARCHAR (6),
  44. CONVERT (INT,
  45. SUBSTRING ([sa].[first_page], 6, 1) +
  46. SUBSTRING ([sa].[first_page], 5, 1))) +
  47. ':' + CONVERT (VARCHAR (20),
  48. CONVERT (INT,
  49. SUBSTRING ([sa].[first_page], 4, 1) +
  50. SUBSTRING ([sa].[first_page], 3, 1) +
  51. SUBSTRING ([sa].[first_page], 2, 1) +
  52. SUBSTRING ([sa].[first_page], 1, 1))) +
  53. ')' AS [First Page],
  54. '(' + CONVERT (VARCHAR (6),
  55. CONVERT (INT,
  56. SUBSTRING ([sa].[root_page], 6, 1) +
  57. SUBSTRING ([sa].[root_page], 5, 1))) +
  58. ':' + CONVERT (VARCHAR (20),
  59. CONVERT (INT,
  60. SUBSTRING ([sa].[root_page], 4, 1) +
  61. SUBSTRING ([sa].[root_page], 3, 1) +
  62. SUBSTRING ([sa].[root_page], 2, 1) +
  63. SUBSTRING ([sa].[root_page], 1, 1))) +
  64. ')' AS [Root Page],
  65. '(' + CONVERT (VARCHAR (6),
  66. CONVERT (INT,
  67. SUBSTRING ([sa].[first_iam_page], 6, 1) +
  68. SUBSTRING ([sa].[first_iam_page], 5, 1))) +
  69. ':' + CONVERT (VARCHAR (20),
  70. CONVERT (INT,
  71. SUBSTRING ([sa].[first_iam_page], 4, 1) +
  72. SUBSTRING ([sa].[first_iam_page], 3, 1) +
  73. SUBSTRING ([sa].[first_iam_page], 2, 1) +
  74. SUBSTRING ([sa].[first_iam_page], 1, 1))) +
  75. ')' AS [First IAM Page]
  76. FROM
  77. sys.system_internals_allocation_units AS [sa],
  78. sys.partitions AS [sp]
  79. WHERE
  80. [sa].[container_id] = [sp].[partition_id]
  81. AND [sp].[object_id] =
  82. (CASE WHEN (@object IS NULL)
  83. THEN [sp].[object_id]
  84. ELSE OBJECT_ID (@object)
  85. END);
  86. GO
  87.  
  88. EXEC sys.sp_MS_marksystemobject [sp_AllocationMetadata];
  89. GO
  90.  
  91. --USE [AdventureWorks];
  92. --GO
  93. --EXEC [sp_AllocationMetadata] N'HumanResources.Employee';
  94. --GO

个人更喜欢使用DBCC EXENTINFO来查看

--================================================================================

  1. --===========================
  2. --插入数据后查看
  3. DBCC EXTENTINFO('TestDB','MixedTest')

PS:注意上面8个数的Ext_Size为1,代表使用混合区

--================================================================================

  1. --===================================
  2. --在线重建索引后查看
  3. ALTER INDEX [MixedTest_CL]
  4. ON [MixedTest] REBUILD
  5. WITH(ONLINE=ON)
  6.  
  7. DBCC EXTENTINFO('TestDB','MixedTest')

对比第一次的数据页ID,会发现重建后的索引,使用新的数据页,但是仍会为表分配混合区。

--================================================================================

  1. --===================================
  2. --脱机重建索引后查看
  3. ALTER INDEX [MixedTest_CL]
  4. ON [MixedTest] REBUILD
  5. WITH(ONLINE=OFF)
  6.  
  7. DBCC EXTENTINFO('TestDB','MixedTest')

在脱机重建索引情况下,仍会为表分配混合区。

--=========================================================================

使用DROP_EXISTING=ON选项创建索引

  1. --===========================
  2. --使用DROP_EXISTING=ON选项创建索引
  3. CREATE CLUSTERED INDEX [MixedTest_CL]
  4. ON [MixedTest] ([c1])
  5. WITH(DROP_EXISTING=ON );
  6.  
  7. DBCC EXTENTINFO('TestDB','MixedTest')

使用DROP_EXISTING=ON选项创建索引,仍会为表分配混合区。

--================================================================================

  1. --===========================
  2. --删除再创建索引
  3. DROP INDEX [MixedTest_CL]
  4. ON [MixedTest]
  5. GO
  6. CREATE CLUSTERED INDEX [MixedTest_CL]
  7. ON [MixedTest] ([c1])
  8. GO
  9. DBCC EXTENTINFO('TestDB','MixedTest')

删除再创建索引,仍会为表分配混合区。

--================================================================================

  1. --===================================
  2. --启用TF1118后,脱机重建索引后查看
  3. DBCC TRACEON(1118,-1)
  4.  
  5. ALTER INDEX [MixedTest_CL]
  6. ON [MixedTest] REBUILD
  7. WITH(ONLINE=OFF)
  8.  
  9. DBCC EXTENTINFO('TestDB','MixedTest')

在开启1118后,不再为对象分配混合区

--===============================================================================

部分同学会疑惑,为什么不一定总是8个页位于混合区中,个人理解是最开始存到到混合区的8个页,在后面的索引操作中,发生了数据页合并和移动等情况,因此导致原来在混合区的数据页被回收或移动到其他统一区上,因此导致存在混合区的数据页小于8个

Paul的原文如下:

there are only 7 mixed pages in the singe-page slot array above. What happened? The answer is that the offline index rebuild ran in parallel, with each thread building a partial index, and then these are stitched together. The ‘stitching together’ operation will cause some of the non-leaf index pages to be deallocated as their contents are merged together. This explains the deallocated page that was originally tracked by entry 3 in the slot array.

--===============================================================================

总结:在不开启1118条件下,无论是脱机还是联机,还是删除重建,无论是多线程还是单线程,实现各部相同,但都会为新表和索引分配混合区上的页。

--===============================================================================

问题1 :在MSDN上有“如果对现有表创建索引,并且该表包含的行足以在索引中生成 8 页,则对该索引的所有分配都使用统一区进行。”

但是经过测试,发现仍会分配混合区。

MSDN连接:http://msdn.microsoft.com/zh-cn/library/ms190969(v=sql.105).aspx

--==============================================================================

各位大师,猩猩,妹子来啦,此次该有掌声

曲演杂坛--重建索引后,还使用混合分区么?(Are mixed pages removed by an index rebuild?)的更多相关文章

  1. 曲演杂坛--一条DELETE引发的思考

    原文:曲演杂坛--一条DELETE引发的思考 场景介绍: 我们有一张表,专门用来生成自增ID供业务使用,表结构如下: CREATE TABLE TB001 ( ID ,) PRIMARY KEY, D ...

  2. 曲演杂坛--使用CTE时踩的小坑:No Join Predicate

    在一次系统优化中,意外发现一个比较“坑”的SQL,拿出来供大家分享. 生成演示数据: --====================================== --检查测试表是否存在 IF(O ...

  3. 曲演杂坛--使用ALTER TABLE修改字段类型的吐血教训

    --===================================================================== 事件起因:开发发现有表插入数据失败,查看后发现INT类型 ...

  4. 曲演杂坛--蛋疼的ROW_NUMBER函数

    使用ROW_NUMBER来分页几乎是家喻户晓的东东了,而且这东西简单易用,简直就是程序员居家必备之杀器,然而ROW_NUMBER也不是一招吃遍天下鲜的无敌BUG般存在,最近就遇到几个小问题,拿出来供大 ...

  5. 曲演杂坛--当ROW_NUMBER遇到TOP

    值班期间研发同事打来电话,说应用有超时,上服务器上检查发现有SQL大批量地执行,该SQL消耗IO资源较多,导致服务器存在IO瓶颈,细看SQL,发现自己都被整蒙了,不知道这SQL是要干啥,处理完问题赶紧 ...

  6. 曲演杂坛--特殊字符/生僻字与varchar

    对于中文版的SQL SERVER,默认安装后使用的默认排序规则为Chinese_PRC_CI_AS,在此排序规则下,使用varchar类型来可以“正常存取”存放中文字符以及一些东南亚国家的字符,同时v ...

  7. 曲演杂坛--为什么SELECT语句会被其他SELECT阻塞?

    很多刚入门的DBA在捕获阻塞得时候,会问这么一个问题“为什么这个SELECT语句被那个SELECT语句阻塞了,难道不是共享锁么?” 让我们来做个小测试,首先准备一些测试数据: --========== ...

  8. 曲演杂坛--HASH的一点理解

    HASH,百度百科上做如下定义: Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射, pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列 ...

  9. 曲演杂坛--EXISTS语句

    通常在我写EXISTS语句时,我会写成IF EXISTS(SELECT TOP(1) 1 FROM XXX),也没细细考究过为什么要这么写,只是隐约认为这样写没有啥问题,那今天就深究下吧! 首先准备测 ...

随机推荐

  1. 百度BAE部署微信开发环境

    这里会弹出一个SVN的账户和密码,这个账户和密码就是你百度的账户和密码 将项目导出WAR包到SVN的客户端目录里面 然后右键SVN Commit提交代码 部署列表有新版本 快捷发布 tocken认证失 ...

  2. 一些常用的c++系统函数

    数学<cmath><math.h>: 1 三角函数 double sin (double); double cos (double); double tan (double); ...

  3. js字符串解析成数字

    parseInt() 先把参数转换成字符串:左边有连续的数字则返回数值,若没有则返回NaN. console.log('parseInt(null)',parseInt(null)); // NaN ...

  4. IDEA 工具下导出文件及文件的目录结构插件

    idea导出增量补丁插件 有时候需要导出IDEA的文件目录结构,即导出  指定修改后的JAVA文件编译后的CLASS .或者是修改过的jsp.配置文件等, 装载此插件,即可以完成导出文件  及文件的目 ...

  5. mvc 封装控件使用mvcpager

    具体使用如下: 前台部分: @RenderPage("~/Views/Controls/_Pagebar.cshtml", new PageBar { pageIndex = Mo ...

  6. mysql简单实现查询结果添加序列号的方法

    方法1: SELECT @rownum :=@rownum + 1 AS rownum, t.* FROM integral_system_user t, (SELECT @rownum := 0) ...

  7. BZOJ 1211[HNOI2004]树的计数 - prufer数列

    描述 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi) ...

  8. 前后台交互(打开前端页面,不传递任何数据,发送ajax请求)

    1.打开前端,不传递任何数据 <script src="./jquery.min.js"></script> <script> $(docume ...

  9. [Git]Git的常用命令

    Update: git status git diff wq git commit -am "why update files" git push Add: git add . g ...

  10. winsock select 学习代码(2)

    之前文章的改进版 服务器仅仅接受客户端发送的字符串并显示 客户端可以调节发送数目 但是不能超过64 // SelectServer.cpp : 定义控制台应用程序的入口点. // #include & ...