SQL Server表空间碎片化回收的实现

目录
  • 1 锁片化的产生
    • 1.1 产生碎片化的原因
    • 1.2 碎片化的影响
    • 1.3 定位碎片化
  • 2 碎片化处理
    • 2.1 删除并重建聚集索引
    • 2.2 DROP_EXISTING
    • 2.3 DBCC DBREINDEX
    • 2.4 DBCC INDEXDEFRAG
  • 3 空间回收
  • 参考链接:

1 锁片化的产生

1.1 产生碎片化的原因

1、在B-tree索引中,表数据按照聚集索引的排序进行物理存储,若聚集索引离散化比较严重,那么可能会出现较为严重的碎片化问题;

2、随着业务的DML操作,会伴随着数据页分裂的情况,这种情况下也会导致表空间碎片化问题;

3、大表通过delete清理无效历史数据,delete产生碎片化空间;

1.2 碎片化的影响

表空间碎片化越严重越容易影响对该表的查询效率,这是因为当表碎片化比较严重时,数据库根据执行计划扫描满足需求的数据页会扫描较多“无效页面”,导致查询操作需要更多的IO消耗。

1.3 定位碎片化

1、在SQL Server中,可以通过DBCC SHOWCONTIG的方式查看表空间碎片化的一些统计信息,具体语法如下:

--查看数据库中所有索引的碎片信息
use ${数据库名}
DBCC SHOWCONTIG WITH ALL_INDEXES
--查看指定表的所有索引的碎片信息
DBCC SHOWCONTIG (${表名}) WITH ALL_INDEXES
--查看指定表、指定索引的碎片信息
DBCC SHOWCONTIG (${表名},${索引名})

2、通过sys.dm_db_index_physical_stats()查看索引碎片化

SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(N'db1'), OBJECT_ID(N'db1.dbo.users'), NULL, NULL , 'LIMITED');
SELECT * FROM sys.dm_db_index_physical_stats(DB_ID(N'db1'), OBJECT_ID(N'db1.dbo.users'), NULL, NULL , 'DETAILED');

重点关注:

  • avg_fragment_size_in_pages : 该参数值越大,范围扫描的性能越好
  • avg_fragmentation_in_percent :对于heap表,该参数表示区碎片百分比;对于index,该参数表示逻辑碎片;该参数越大表示表的碎片化越严重,需要通过 Reorganize or Rebuild Indexes 来进行碎片化回收
  • avg_page_space_used_in_percent : 该参数表示数据页的填充程度,一般小于100%,但是该参数越小,表示数据页面碎片化情况越严重。若想要数据页使用率的问题,必须进行索引重建操作
  • fragment_count : 碎片化数据页数
  • page_count : 扫描数据页数

3、通过统计信息查看数据库碎片化空间Top表信息

SELECT
   db_name() as DbName,
    t.NAME AS TableName,
    s.Name AS SchemaName,
    p.rows AS RowCounts,
    SUM(a.total_pages) * 8 AS TotalSpaceKB,
    CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS 总共占用空间MB,
    SUM(a.used_pages) * 8 AS 总使用空间KB,
    CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC(36, 2)) AS 总使用空间MB,
    (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS 碎片化空间KB,
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS 碎片化空间MB
FROM
    sys.tables t
INNER JOIN
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN
    sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN
    sys.schemas s ON t.schema_id = s.schema_id
WHERE
    t.is_ms_shipped = 0
    AND i.OBJECT_ID > 0
GROUP BY
    t.Name, s.Name, p.Rows
ORDER BY
    总共占用空间MB desc

2 碎片化处理

由于表数据是根据聚集索引排序进行物理存储,所以当表碎片化比较严重时,可以通过对聚集索引的重新组织来进行碎片化空间回收,重建索引的方式也有比较多方式,主要如下:

2.1 删除并重建聚集索引

该方式其实就是将碎片化比较严重的表,先通过drop index删除其聚集索引,然后通过create index或者alter table重建聚集索引。该方式的特点是:

  • 执行删除聚集索引后,会影响该表有关利用该索引进行查询的SQL执行效率
  • 执行删除聚集索引,也会导致该表相关的非聚集索引重建
  • 在重建聚集索引期间,会获取相应的Sch-M锁,阻塞业务正常读写操作,且创建聚集索引后也会导致相应的非聚集索引重建
  • 该方式会将整张表数据进行重新组织,可回收最大限度的碎片化空间

2.2 DROP_EXISTING

使用DROP_EXISTING进行重建索引,也是对聚集索引的删除重建,但是该方式在方法一的基础上做了一些优化:

  • 删除聚集索引时,会保留主键索引的键值,避免了删除、重建聚集索引时对非聚集索引的重建
  • 执行DROP_EXISTING重建索引期间,仍然会对正常业务读写操作造成阻塞
  • 该方式会将整张表数据进行重新组织,可回收最大限度的碎片化空间

基本语法:

CREATE INDEX ${index_name} ON T(${index_col})  WITH (DROP_EXISTING = ON)

2.3 DBCC DBREINDEX

DBCC DBREINDEX也是通过对索引的删除以及重建来实现碎片化回收。根据数据库版本(企业版or非企业版)以及索引类型(非聚集or聚集),该操作是可以实现在线或者离线操作。

  • 在企业版数据引擎中,对于非聚集索引的索引重建可以通过在线的方式进行操作
  • 在线索引重建期间,虽然不阻塞正常业务读写操作,但还是对应的DML操作执行效率还是会有所下降
  • 离线索引重建期间,阻塞业务读写
  • 对于在线索引重建,可以进行暂停或者终止。但是暂停期间应用会影响该表的DML执行效率,如果后续不继续索引的重建操作,请直接终止而不是暂停
  • 该方式会将整张表数据进行重新组织,可回收最大限度的碎片化空间

基本语法:

-- 重建指定索引
USE ${db_name};   
GO  
DBCC DBREINDEX ('${schema_name}.${table_name}', ${index_name},80);  
GO

-- 重建指定表全部索引
USE ${db_name};   
GO  
DBCC DBREINDEX ('${schema_name}.${table_name}', ' ', 70);  
GO

2.4 DBCC INDEXDEFRAG

该方式的实现逻辑与以上三种大有不同,DBCC INDEXDEFRAG并非完全重新组织整张表的b-tree结构:

DBCC INDEXDEFRAG按照索引键的逻辑顺序,通过压缩索引页里的行然后删除那些由此产生的不必要的碎片化数据页、删除完全碎片化数据页面的方式来进行碎片化空间的回收
该方式执行期间不阻塞业务读写操作
该方式下可回收的碎片化空间效果可能不如以上三种索引重建的方式
基本语法:

DBCC INDEXDEFRAG (${db_name}, '${schema_name}.${table_name}', ${index_name});

3 空间回收

需要注意的是,在SQL Server数据库,我们对表空间数据进行碎片化处理、或者truncate清空无效历史数据,这些释放出来的空间只是空出来,当有新数据写入时,优先使用这些空出来的数据页,而不是再向OS申请新的数据空间扩展。所以这部分并不会直接释放给OS,如果我们想要达到降低整个OS的磁盘空间使用率的话,还需要对数据库的数据文件进行收缩。

1、检查数据文件空间使用率

-- 检查数据库文件空间使用率
SELECT a.name [文件名称] ,cast(a.[size]*1.0/128 as decimal(12,1)) AS [文件设置大小(MB)] ,
    CAST( fileproperty(s.name,'SpaceUsed')/(8*16.0) AS DECIMAL(12,1)) AS [文件所占空间(MB)] ,
    CAST( (fileproperty(s.name,'SpaceUsed')/(8*16.0))/(s.size/(8*16.0))*100.0 AS DECIMAL(12,1)) AS [所占空间率%] ,
    CASE WHEN A.growth =0 THEN '文件大小固定,不会增长' ELSE '文件将自动增长' end [增长模式] ,CASE WHEN A.growth > 0 AND is_percent_growth = 0
    THEN '增量为固定大小' WHEN A.growth > 0 AND is_percent_growth = 1 THEN '增量将用整数百分比表示' ELSE '文件大小固定,不会增长' END AS [增量模式] ,
    CASE WHEN A.growth > 0 AND is_percent_growth = 0 THEN cast(cast(a.growth*1.0/128as decimal(12,0)) AS VARCHAR)+'MB'
    WHEN A.growth > 0 AND is_percent_growth = 1 THEN cast(cast(a.growth AS decimal(12,0)) AS VARCHAR)+'%' ELSE '文件大小固定,不会增长' end AS [增长值(%或MB)] ,
    a.physical_name AS [文件所在目录] ,a.type_desc AS [文件类型]
FROM sys.database_files a
INNER JOIN sys.sysfiles AS s  ON a.[file_id]=s.fileid
LEFT JOIN sys.dm_db_file_space_usage b ON a.[file_id]=b.[file_id] ORDER BY a.[type]

2、收缩数据文件

USE [${db_name}]
GO
DBCC SHRINKDATABASE(N'${db_name}' )
GO

参考链接:

https://docs.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes?view=sql-server-ver15

https://docs.microsoft.com/en-us/sql/t-sql/statements/create-index-transact-sql?view=sql-server-ver15

到此这篇关于SQL Server表空间碎片化回收的实现的文章就介绍到这了,更多相关SQL Server表空间碎片化回收内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Mysql在线回收undo表空间实战记录

    1 Mysql5.6 1.1 相关参数 MySQL 5.6增加了参数innodb_undo_directory.innodb_undo_logs和innodb_undo_tablespaces这3个参数,可以把undo log从ibdata1移出来单独存放. innodb_undo_directory:指定单独存放undo表空间的目录,默认为.(即datadir),可以设置相对路径或者绝对路径.该参数实例初始化之后虽然不可直接改动,但是可以通过先停库,修改配置文件,然后移动undo表空间文件的方

  • Oracle中查看表空间使用率的SQL脚本分享

    复制代码 代码如下: /* Formatted on 2012/5/31 14:51:13 (QP5 v5.185.11230.41888) */ SELECT D.TABLESPACE_NAME,        SPACE || 'M' "SUM_SPACE(M)",        BLOCKS "SUM_BLOCKS",        SPACE - NVL (FREE_SPACE, 0) || 'M' "USED_SPACE(M)",   

  • mysql 表空间及索引的查看方法

    1.查看索引 (1)单位是GB SELECT CONCAT(ROUND(SUM(index_length)/(1024*1024*1024), 2), ' GB') AS 'Total Index Size' FROM information_schema.TABLES WHERE table_schema LIKE 'database'; +------------------+ | Total Index Size | +------------------+ | 1.70 GB | +--

  • Oracle表空间查看sql使用情况

    DBA在日常工作中,最重要的一点就是查看表空间的使用情况,去了解是否有表空间满了的情况出现. 具体方法和步骤如下所示: 第一步:打开PLSQL 第二步:新建一个SQL窗口 第三步:输入代码: select a.tablespace_name tablespace_name ,nvl(ceil((1 - b.free / a.total) * 100), 100) "usage_of_tablespace%" ,nvl(b.free, 0) "left_space(M)&quo

  • mysql Innodb表空间卸载、迁移、装载的使用方法

    条件:2台服务器:A和B,需要A服务器上的表迁移到B服务器.Innodb表:sysUser,记录数:351781.以下测试在MySQL 5.5.34中进行.开始处理:1:在B服务器上建立sysUser表,并且执行: 复制代码 代码如下: zjy@B : db_test 09:50:30>alter table sysUser discard tablespace; 2:把A服务器表的表空间(ibd)复制到B服务器的相应数据目录.3:修改复制过来的ibd文件权限: 复制代码 代码如下: chown

  • SQL Server表空间碎片化回收的实现

    目录 1 锁片化的产生 1.1 产生碎片化的原因 1.2 碎片化的影响 1.3 定位碎片化 2 碎片化处理 2.1 删除并重建聚集索引 2.2 DROP_EXISTING 2.3 DBCC DBREINDEX 2.4 DBCC INDEXDEFRAG 3 空间回收 参考链接: 1 锁片化的产生 1.1 产生碎片化的原因 1.在B-tree索引中,表数据按照聚集索引的排序进行物理存储,若聚集索引离散化比较严重,那么可能会出现较为严重的碎片化问题: 2.随着业务的DML操作,会伴随着数据页分裂的情况

  • MySQL 表空间碎片的概念及相关问题解决

    背景 经常使用 MySQL 的话,会发现 MySQL 数据文件的磁盘空间一般会不停的增长,而且有时候删了数据或者插入一批数据的时候,磁盘空间有时候还会毫无变化.引发这个其妙现象的就是 MySQL 的表空间碎片. 什么是表空间碎片? 表空间碎片指的是表空间中存在碎片,形象一点来比喻的话,就像是一张 A4 纸,"表空间碎片"就像是把这张 A4 纸撕碎,再重新拼起来,各个碎片之间都会有一些缝隙存在,这些缝隙就是"表空间碎片".重新拼起来的碎片实际上会比完整的 A4 纸大上

  • MySQL 清除表空间碎片的实例详解

    MySQL 清除表空间碎片的实例详解 碎片产生的原因 (1)表的存储会出现碎片化,每当删除了一行内容,该段空间就会变为空白.被留空,而在一段时间内的大量删除操作,会使这种留空的空间变得比存储列表内容所使用的空间更大: (2)当执行插入操作时,MySQL会尝试使用空白空间,但如果某个空白空间一直没有被大小合适的数据占用,仍然无法将其彻底占用,就形成了碎片: (3)当MySQL对数据进行扫描时,它扫描的对象实际是列表的容量需求上限,也就是数据被写入的区域中处于峰值位置的部分: 例如: 一个表有1万行

  • sql server 表结构修改方法

    如果我们需要修改sql server表结构,应该怎么做呢?下面就将教您如何修改sql server表结构的方法,希望对您学习sql server表结构方面能够有所帮助. 向sql server表中增加一个varchar列: ALTER TABLE distributors ADD COLUMN address varchar(30); 从sql server表中删除一个字段: ALTER TABLE distributors DROP COLUMN address RESTRICT; 在一个操作

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

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

  • SQL Server表分区删除详情

    目录 一.引言 二.演示 2.1.数据查询 2.1.1. 查看分区元数据 2.1.2.统计每个分区的数据量 2.2.删除实操 2.2.1.合并原表分区 2.2.2.备份原表所有索引的创建脚本 2.2.3.删除原表所有索引 2.2.4.创建临时表 2.2.5.更改原表数据空间类型 2.2.6.移动原表分区数据到临时表 2.2.7.创建原表所有索引 到临时表 2.2.8.删除原表 2.2.9.删除分区方案和分区函数 2.2.10重命名表名 一.引言 删除分区又称为合并分区,简单地讲就是将多个分区的数

  • 详解SQL Server表和索引存储结构

    本文详细分析了SQL Server中表和索引结构存储的原理以及对于如何加快搜索速度和提高效率等方面做了详细的分析,以下是主要内容. 下图显示了表的存储组织,每张表有一个对应的对象ID,并且包含一个或多个分区,每个分区会有一个堆或者多个B树,堆或者B树的结构是预留的.每个堆或者是B树都有三个分配单元用来存放数据,分别是数据.LOB.行溢出,使用最多的分配单元是数据.如果有LOB数据或者是长度超过8000字节的记录,则可能有另外的LOB分配单元和行溢出分配单元. 小总结: 一个表可以有多个分区,但是

  • 把CSV文件导入到SQL Server表中的方法

    有时候我们可能会把CSV中的数据导入到某个数据库的表中,比如做报表分析的时候. 对于这个问题,我想一点也难不倒程序人员吧!但是要是SQL Server能够完成这个任务,岂不是更好! 对,SQL Server确实有这个功能. 首先先让我们看一下CSV文件,该文件保存在我的D:盘下,名为csv.txt,内容是: 现在就是SQL Server的关键部分了: 我们使用的是SQL Server的BULK INSERT命令,关于该命令的详细解释,请点击此处: 我们先在SQL Server中建立用于保存该信息

  • SQL Server 表变量和临时表的区别(详细补充篇)

    一.表变量 表变量在SQL Server 2000中首次被引入.表变量的具体定义包括列定义,列名,数据类型和约束.而在表变量中可以使用的约束包括主键约束,唯一约束,NULL约束和CHECK约束(外键约束不能在表变量中使用).定义表变量的语句是和正常使用Create Table定义表语句的子集.只是表变量通过DECLARE @local_variable语句进行定义. 表变量的特征: 1.表变量拥有特定作用域(在当前批处理语句中,但不在任何当前批处理语句调用的存储过程和函数中),表变量在批处理结束

  • SQL server 表数据改变触发发送邮件的方法

    今天遇到一个问题,原有生产系统正在健康运行,现需要监控一张数据表,当增加数据的时候,给管理员发送邮件. 领到这个需求后,有同事提供方案:写触发器触发外部应用程序.这是个大胆的想法啊,从来没写过这样的触发器. 以下是参考文章: 第一种方法: 触发器调用外部程序. xp_cmdshell http://www.jb51.net/article/90714.htm 第一篇提供的方法是需要开启xp_cmdshell 先开启xp_cmdshell 打开外围应用配置器-> 功能的外围应用配置器-> 实例名

随机推荐