zoukankan      html  css  js  c++  java
  • 转载SQLServer索引碎片

    一、总结

    1、数据库的存储本身是无序的,建立聚集索引之后,就会按照聚集索引的物理顺序存入硬盘;

    2、建立索引完全是为了提升读取的速度,相对写入的速度就会降低,没有索引的表写入时最快的,但是大多数系统读的频率要高于写的频率;

    3、索引碎片分为内部碎片和外部碎片。

      内部碎片:是指索引页没有100%存储满,有剩余空间,这就是内部碎片;产生原因是在insert或者update数据时,该页不足以放下新增或更新的数据,造成分页,导致索引页的平均密度变小,就产生了内部碎片;

      外部碎片:是指做插入或更新操作时,原来页无法容纳新的行,导致分页(分页会将原来页大约一半的数据放到新页上,达到一个平衡状态),而新的页和原来的页在物理上又不连续了(分页之前,他们之间有好多页面),而聚集索引要求行之前是连续的,所以分页后,新叶和原来页物理上的不连续是造成外部碎片的原因。

    4、修改填充因子,也有可能解决索引碎片的问题,一千万的数据量修改填充因子用了1分钟(只是测试,表没有做删除的操作);

    5、索引碎片查出的记录数(record_count)与直接select count(*)查出的数据量可能不一样,具体解释参考下面对字段意思的解释处;

    7.如果数据库里有批量数据的删除,导致avg_page_space_used_in_percent页的百分比变小,产生了碎片,这个时候可以通过收缩数据文件来增大页百分比,释放更多的空间(已测试过,但是做数据文件的收缩要慎重)

    二、具体SQL操作

    1.查看索引碎片

    命令:SELECT page_count,avg_page_space_used_in_percent,record_count,
    avg_record_size_in_bytes,avg_fragmentation_in_percent,fragment_count
    FROM sys.dm_db_index_physical_stats(DB_ID('run'),object_id('dbo.Person'),NULL,NULL,'sampled')

     page_count:索引或数据页的总数

    avg_page_space_used_in_percent:平均数据页面使用空间的百分比

    record_count:记录数,该数可能与对表查询select count(*)查出的结果值不一样,这是因为一行可能包含多个记录,比如LOB字段或可变长度的数据等等,详情参考官方解释

    avg_record_size_in_bytes:平均每条记录数的大小(字节)

    avg_fragmentation_in_percent:索引的逻辑碎片,按百分比计算,值越小表示碎片越少,平均每个区的剩余空间(也就是碎片的百分比)

    fragment_count:叶级别中的碎片数(外部碎片的数量),也有可能是小的表保存在混合区上

    官方参考地址:https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008-r2/ms188917%28v%3dsql.105%29

    2.显示数据库里所有索引的碎片信息

    命令:

    use [run]
    DBCC SHOWCONTIG WITH ALL_INDEXES

     3.显示指定表的所有索引的碎片信息

    命令:

    use [run]
    DBCC SHOWCONTIG(T1) WITH ALL_INDEXES

     4.显示指定索引的碎片信息

    命令:

    DBCC SHOWCONTIG(T1,pk_name)

     查出结果的解释:

      扫描页数:该表的数据存储的页数;

      扫描区数:一个区有8页,用扫描页数除以8可以得出估计的区数,如果扫描出的区数比你算出的要多,说明存在外部碎片,比算出的值高的多,说明外部碎片越多(如果数据量少的话不能作为参考值,比如扫面页数少于8页,就可能是存储在混合区里,不是单独给该表分配的区);

      扫描密度:最佳值:实际值,该比值应该尽可能接近100%,低了说明有外部碎片;

      逻辑扫描碎片:无序页的百分比,该比值应该在0%到10%之间,高了则说明有外部碎片;

      区扫描碎片:无序扩展盘区在扫面索引叶级页中所占的百分比。该百分比高,说明有外部碎片;

      每页的平均可用字节数:每页还剩余的空间,剩的越多说明有内部碎片,这个值要参考是否有设置填充因子,默认填充因子是0,就是页100%填充数据,如果填充因子是80%,就表示只填充80%的数据,剩下的20%留着给insert和update使用,以防做插入和更新时出现分页的情况。

      平均密度:每页上数据量的密度,该值越高,表示每页填充的越满,值越低,表示每页上剩余空间越多,内部碎片越多。这个是相对的,要看系统读写比例,密度越低,页上剩余的空间大,插入更新数据时的性能就会越好(不会造成分页);相反密度越高,页上剩余空间小,插入更新数据时可能会造成分页,性能就会低,相反查询的性能就会好,因为扫描的页少,跨区扫描页少,所以查询性能会好;

    5、查看索引的填充因子

    命令:

    select object_name(object_id) as tname,name as indexName,type_desc,fill_factor
    from run.sys.indexes where name='pk_name'

    6.修改索引的填充因子

    注:也是在图形化页面修改,也可以生成脚本
    命令:alter index pk_name on dbo.T1 rebuild with (fillfactor=80)

    7、打开IO统计,查看查询读取磁盘的IO次数

    命令:

    set statistics io on
    select top 100 col2 from run.dbo.T1 where col2='99'
    set statistics io off

     三、索引碎片的解决办法

    1、删除索引重新创建

      这种操作会造成阻塞,会导致非聚集索引重建2次(删除重建,建立重建),数据量大的情况下耗时非常长,生产环境不建议这么做。

    2.使用drop_existing语句重建索引

      该方法可以避免重建2次索引,因为该语句是原子性的,不会导致非聚集索引重建2次,但同样会造成阻塞。

      该方法可以重新创建使用约束的索引(如:唯一性约束)

    命令:create unique clustered index pk_name on T1(Col1) with (drop_existing=on)

     3.使用alter index rebuild语句重建索引

      该种方式也是重建索引,但是是动态重建索引而不是卸载在重新重建,但是依旧会造成阻塞;

      可以通过online关键字减少锁,但是会造成重建时间加长;

      原子性操作,中途终止会事务回滚;

    命令:

    alter index pk_name on T1 rebuild
    alter index pk_name on T1 rebuild with (online=on)

    alter index all  on T1 rebuild with (online=on) --在线重建所有索引

     4.使用alter index reorganize整理索引页

      该种方式不会重建索引,也不会生成新的页,仅仅是整理叶级数据,不涉及非叶级节点,当遇到加锁的页时跳过,所以不会造成阻塞,但整理效果会比前3种差。

      重整索引不会锁定任何对象,它仅仅是优化当前的B树的叶子节点。

    命令:

    alter index pk_name on T1 reorganize --重整pk_name索引
    alter index all on T1 reorganize --重整所有索引

  • 相关阅读:
    VI命令----用于检索
    NIO框架Mina学习
    Android闹钟开发与展示Demo
    Golang mysql使用举例---连接本地数据库
    mysql通信协议
    大小端定义
    npm是什么
    菜鸟如何学习vue
    cgred不能自动将pid放入tasks
    centos7上为什么不使用libcgroup进行资源限制
  • 原文地址:https://www.cnblogs.com/Alex80/p/14695805.html
Copyright © 2011-2022 走看看