[转]SQL SERVER整理索引碎片测试

SQL SERVER整理索引碎片测试

SQL SERVER整理索引的方法也就这么几种,而且老是自作聪明的加入智能判断很不爽,还是比DBMS_ADVISOR差远了:

1SQL SERVER 2000/2005

查询

2000
use DB_Name
declare @table_id int
set @table_id=object_id(‘Table_Name‘)
dbcc showcontig(@table_id)

2005
SELECT index_id,index_type_desc,avg_fragmentation_in_percent,page_count 
FROM sys.dm_db_index_physical_stats(db_id(), OBJECT_ID(‘Table_Name‘), NULL, NULL , ‘LIMITED‘);

整理

2000
DBCC INDEXDEFRAG (DB_Name, ‘dbo.Table_Name‘, Index_Name)
DBCC DBREINDEX (‘DB_Name.dbo.Table_Name‘,‘‘,100)

2005
ALTER INDEX Index_Name ON dbo.Table_Name REBUILD

以下是一个网上找的不错的例子,链接是:
http://www.cnblogs.com/perfectdesign/archive/2008/02/20/sqlserverreindexrebuild.html
新建一个表:

create table t3
(
i int primary key,
xx varchar(200) not null
)

加入数据:

declare @x int
set @x = 0
while @x <1000
begin                       
insert into t3 values (@x,‘qweasdqweasdqweasdqweqweasdqwe‘)
set @x = @x+1
end

执行动态管理视图:

SELECT index_id,index_type_desc,avg_fragmentation_in_percent,page_count 
FROM sys.dm_db_index_physical_stats
(db_id(), OBJECT_ID(‘t3‘), NULL, NULL , ‘LIMITED‘);

可以看到:

index_id为0表示这个是堆,平均的碎片有33%

现在执行几个可以减少碎片的方法都不管用,不能减少碎片。
包括:

DBCC INDEXDEFRAG (test, ‘dbo.t3‘, PK__t3__0EA330E9)

alter index PK__t3__0EA330E9 on t3
rebuild

dbcc dbreindex (‘t3‘)

这几个方法还有删除重建索引,都不能减少碎片数量。

后来我觉得是因为数据太少了,导致页也很少,数据库可能存在某种智能,判断是否值得去做重建索引的工作,所以加大的数据量:

declare @x int
set @x = 1000
while @x <10000
begin                       
insert into t3 values (@x,‘qweasdqweasdqweasdqweqweasdqwe‘)
set @x = @x+1
end

再执行语句:

SELECT index_id,index_type_desc,avg_fragmentation_in_percent,page_count 
FROM sys.dm_db_index_physical_stats
(db_id(), OBJECT_ID(‘t3‘), NULL, NULL , ‘LIMITED‘);

alter index t3index on t3 rebuild

显示出来了!

结论:
SQL Server在执行相关的操作的时候都会智能去判断是否值得去做,比如在页面数太小的情况下可以不去重建索引,rebuild reindex 。类似的,在SQL Server 2005 里面也多了许多智能的判断来保证一个完整庞大而又不失智能的设计,
比如:
生成查询计划的阀值
缓存机制,缓存的筛选,LRU算法
预读机制
checkpoint减少回滚距离
智能join判断
重编译

了解SQL Server这种类似的软件产品能够为我们在设计产品的时候提供更多的思路想法,即使你了解上面的东西对你的SQL开发也不会有太多帮助。

另外附上几种方式的区别:
reindex是比较好的选择,速度快,但是他不能在线操作
INDEXDEFRAG 比较慢,但是可以在线操作
rebuild建议在碎片较少时采用。

附上微软的重建索引脚本,从里面也可以看出微软根据碎片大小推荐的方式,不过这个要随每个不同的数据库而定。

-- ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @partitioncount bigint;
DECLARE @schemaname sysname;
DECLARE @objectname sysname;
DECLARE @indexname sysname;
DECLARE @partitionnum bigint;
DECLARE @partitions bigint;
DECLARE @frag float;
DECLARE @command varchar(8000);
-- ensure the temporary table does not exist
IF EXISTS (SELECT name FROM sys.objects WHERE name = ‘work_to_do‘)
    DROP TABLE work_to_do;
-- conditionally select from the function, converting object and index IDs to names.
SELECT
    object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, ‘LIMITED‘)
WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR SELECT * FROM work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
FETCH NEXT
   FROM partitions
   INTO @objectid, @indexid, @partitionnum, @frag;

WHILE @@FETCH_STATUS = 0
    BEGIN;
        SELECT @objectname = o.name, @schemaname = s.name
        FROM sys.objects AS o
        JOIN sys.schemas as s ON s.schema_id = o.schema_id
        WHERE o.object_id = @objectid;

        SELECT @indexname = name 
        FROM sys.indexes
        WHERE  object_id = @objectid AND index_id = @indexid;

        SELECT @partitioncount = count (*) 
        FROM sys.partitions
        WHERE object_id = @objectid AND index_id = @indexid;

-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding
IF @frag < 30.0
    BEGIN;
    SELECT @command = ‘ALTER INDEX ‘ + @indexname + ‘ ON ‘ + @schemaname + ‘.‘ + @objectname + ‘ REORGANIZE‘;
    IF @partitioncount > 1
        SELECT @command = @command + ‘ PARTITION=‘ + CONVERT (CHAR, @partitionnum);
    EXEC (@command);
    END;

IF @frag >= 30.0
    BEGIN;
    SELECT @command = ‘ALTER INDEX ‘ + @indexname +‘ ON ‘ + @schemaname + ‘.‘ + @objectname + ‘ REBUILD‘;
    IF @partitioncount > 1
        SELECT @command = @command + ‘ PARTITION=‘ + CONVERT (CHAR, @partitionnum);
    EXEC (@command);
    END;
PRINT ‘Executed ‘ + @command;

FETCH NEXT FROM partitions INTO @objectid, @indexid, @partitionnum, @frag;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;

-- drop the temporary table
IF EXISTS (SELECT name FROM sys.objects WHERE name = ‘work_to_do‘)
    DROP TABLE work_to_do;
GO

BOL的推荐:

avg_fragmentation_in_percent 值 修复语句

> 5% 且 < = 30%


ALTER INDEX REORGANIZE


> 30%


ALTER INDEX REBUILD WITH (ONLINE = ON)*

小于5没必要重建,所以上面的SQL语句还是有得商量的地方。

http://blog.csdn.net/greenery/archive/2008/08/06/2778486.aspx


/**************************************
作用:在线整理索引碎片
时间:2008-5-15
说明:
          根据微软的示例改编
          适用于无法停机重建索引的情况,
          在线整理索引碎片,并更新表的统计信息以增强效果。
          另外可以自定义需要整理的索引的逻辑碎片程度,扫描密度,页数
          必须要在数据库访问较少的时候执行 
***************************************/
CREATE PROC [dbo].[SYS_IndexDrag]
AS
BEGIN

SET NOCOUNT ON
DECLARE @tablename VARCHAR (128)
DECLARE @execstr VARCHAR (255)
DECLARE @objectid INT
DECLARE @indexid INT
DECLARE @frag DECIMAL
DECLARE @maxfrag DECIMAL--逻辑碎片

DECLARE @MaxScanDensity DECIMAL--扫描密度

DECLARE @Page INT --8k页数,设定一个限度对一定大的索引进行整理

DECLARE @TmpName VARCHAR(150)

-- Decide on the maximum fragmentation to allow

SELECT @maxfrag = 30.0
SELECT @MaxScanDensity=70.0
SELECT @Page=400

-- Declare cursor

DECLARE tables CURSOR FOR
   SELECT TABLE_NAME
   FROM INFORMATION_SCHEMA.TABLES
   WHERE TABLE_TYPE = ‘BASE TABLE‘

-- Create the table

CREATE TABLE #fraglist (
   ObjectName CHAR (255),
   ObjectId INT,
   IndexName CHAR (255),
   IndexId INT,
   Lvl INT,
   CountPages INT,
   CountRows INT,
   MinRecSize INT,
   MaxRecSize INT,
   AvgRecSize INT,
   ForRecCount INT,
   Extents INT,
   ExtentSwitches INT,
   AvgFreeBytes INT,
   AvgPageDensity INT,
   ScanDensity DECIMAL,
   BestCount INT,
   ActualCount INT,
   LogicalFrag DECIMAL,
   ExtentFrag DECIMAL)

-- Open the cursor

OPEN tables

-- Loop through all the tables in the database

FETCH NEXT
   FROM tables
   INTO @tablename

WHILE @@FETCH_STATUS = 0
BEGIN
-- Do the showcontig of all indexes of the table

INSERT INTO #fraglist
   EXEC (‘DBCC SHOWCONTIG (‘‘‘ + @tablename + ‘‘‘)
      WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS‘)
    
   FETCH NEXT
      FROM tables
      INTO @tablename
END

-- Close and deallocate the cursor

CLOSE tables
DEALLOCATE tables

-- Declare cursor for list of indexes to be defragged

DECLARE indexes CURSOR FOR
   SELECT ObjectName, ObjectId, IndexId, LogicalFrag
   FROM #fraglist
   WHERE (LogicalFrag >= @maxfrag OR [ScanDensity]<[email protected]) AND [CountPages]>[email protected]
      AND INDEXPROPERTY (ObjectId, IndexName, ‘IndexDepth‘) > 0

-- Open the cursor

OPEN indexes

-- loop through the indexes

FETCH NEXT
   FROM indexes
   INTO @tablename, @objectid, @indexid, @frag

WHILE @@FETCH_STATUS = 0
BEGIN
  
   --在线整理碎片

PRINT ‘Executing DBCC INDEXDEFRAG (0, ‘ + RTRIM(@tablename) + ‘,
      ‘ + RTRIM(@indexid) + ‘) - fragmentation currently ‘
       + RTRIM(CONVERT(varchar(15),@frag)) + ‘%‘
   SELECT @execstr = ‘DBCC INDEXDEFRAG (0, ‘ + RTRIM(@objectid) + ‘,
       ‘ + RTRIM(@indexid) + ‘)‘
   EXEC (@execstr)
  
   --更新统计信息

IF @TmpName<>@tablename
   BEGIN
        SET @[email protected]
        EXEC(‘UPDATE STATISTICS ‘[email protected]) 
   END
    
   FETCH NEXT
      FROM indexes
      INTO @tablename, @objectid, @indexid, @frag
END

-- Close and deallocate the cursor

CLOSE indexes
DEALLOCATE indexes

-- Delete the temporary table

DROP TABLE #fraglist

END

GO

时间: 2024-11-29 01:58:36

[转]SQL SERVER整理索引碎片测试的相关文章

SQL Server通过整理索引碎片和重建索引提高速度

SQL Server数据库操作中,当数据库中的记录比较多的时候,我们可以通过索引来实现查询.但是当索引碎片太多的时候,就会很严重地影响到查询的速度.这时候我们可以采取两种方法来解决:一种时整理索引碎片,另一种是重建索引.本文主要介绍了这一过程,接下来就让我们来一起了解一下吧. 检查索引碎片DBCC SHOWCONTIG(表),得到如下结果: DBCC SHOWCONTIG 正在扫描 'A' 表... 表: 'A'(884198200):索引 ID: 1,数据库 ID: 13 已执行 TABLE 

从性能的角度谈SQL Server聚集索引键的选择

简介 在SQL Server中,数据是按页进行存放的.而为表加上聚集索引后,SQL Server对于数据的查找就是按照聚集索引的列作为关键字进行了.因此对于聚集索引的选择对性能的影响就变得十分重要了.本文从旨在从性能的角度来谈聚集索引的选择,但这仅仅是从性能方面考虑.对于有特殊业务要求的表,则需要按实际情况进行选择. 聚集索引所在的列或列的组合最好是唯一的 这个原因需要从数据的存放原理来谈.在SQL Server中,数据的存放方式并不是以行(Row)为单位,而是以页为单位.因此,在查找数据时,S

检测和整理索引碎片

索引碎片的检测和整理 存储数据是为了查找数据,存储结构影响数据查找的性能.对无序数据进行查找,最快的查找算法是哈希查找:对有序数据进行查找,最快的查找算法是平衡树查找.在传统的关系型数据库中,聚集索引和非聚集索引都是平衡树(B-Tree)类型的存储结构,用于顺序存储数据,便于实现数据的快速查找.除了提升数据查找的性能之外,索引还能减少硬盘IO和内存消耗.通常情况下,硬盘IO是查找性能的瓶颈,由于索引是数据表的列的子集,这意味着,索引只存储部分列的数据,占用的硬盘空间比全部列少了很多,因此,数据库

深入非聚集索引:楼梯SQL Server二级索引

通过大卫·杜兰特,2017/10/18(第一次出版:2014/11/26) 该系列 本文是楼梯系列的一部分:SQL Server的阶梯索引 索引数据库设计的基础,告诉开发人员使用数据库设计者的意图. 不幸的是索引时往往是后加上的性能问题出现. 终于在这里是一个简单的系列文章,应该让任何数据库专业迅速"加速" SQL Server的一级索引楼梯介绍了SQL Server索引,一般来说,和非聚集索引. 作为我们的第一个案例研究中,我们演示了索引的潜在好处,当从一个表中检索单个行. 在这个层

T-SQL查询进阶--理解SQL Server中索引的概念,原理以及其他

简介 在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能,在OLAP中尤其明显.要完全理解索引的概念,需要了解大量原理性的知识,包括B树,堆,数据库页,区,填充因子,碎片,文件组等等一系列相关知识,这些知识写一本小书也不为过.所以本文并不会深入讨论这些主题. 索引是什么 索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 精简来说,索引是一种结构.

SQL Server查看索引重建、重组索引进度

原文:SQL Server查看索引重建.重组索引进度 相信很多SQL Server DBA或开发人员在重建或重组大表索引时,都会相当郁闷,不知道索引重建的进度,这个对于DBA完全是一个黑盒子,对于系统负载非常大的系统或维护窗口较短的系统,你会遇到一些挑战.例如,你创建索引的时候,很多会话被阻塞,你只能取消创建索引的任务.查看这些索引维护操作的进度.预估时间对于我们有较大的意义,需要根据这个做一些决策.下面我们来看看看看如何获取CREATE INDEX.ALTER INDEX REBUILD.AL

SQL Server获取索引创建时间&amp;重建时间&amp;重组时间

原文:SQL Server获取索引创建时间&重建时间&重组时间 之前写过一篇博客"SQL Server中是否可以准确获取最后一次索引重建的时间?",里面主要讲述了三个问题:我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild)的时间? 最后一次索引重组(INDEX REORGANIZE)的时间呢?,当时得出的结论,答案是我们无法准确的找到索引的创建时间.最后一次索引重组时间,最后一次索引重建的时间.但是最近看到一篇博客"SQL Server

公司内部培训SQL Server传统索引结构PPT分享

公司内部培训SQL Server传统索引结构PPT分享 下载地址 http://files.cnblogs.com/files/lyhabc/SQLServer%E4%BC%A0%E7%BB%9F%E7%B4%A2%E5%BC%95%E7%BB%93%E6%9E%84.ppt PPT有不对的地方,多多拍砖o(∩_∩)o

SQL Server 的索引结构实例

目前SQL Server 的索引结构如下: 这个是聚集索引的存放形式: 非聚集索引的方式如下: 它们是以B+树的数据结构存放的. 相信大家都看过类似的图,但是没有直观的认识,下面举一个实际的例子来说明图的结构. USE Test --1.创建表,指定主键(会自动创建聚集索引) CREATE TABLE Person ( Id int NOT NULL IDENTITY, Name varchar(10) NOT NULL, Sex varchar(2) NOT NULL, CONSTRAINT