【基本优化实践】【1.2】索引优化——查看堆表、查看索引使用情况、查看索引碎片率

【1】查看堆表

--查看堆表且行大于等于10W的
select * from (
SELECT tables.NAME,
       (SELECT rows
        FROM   sys.partitions
        WHERE  object_id = tables.object_id
               AND index_id = 0 -- 0 is for heap
               -- 1 is for clustered index
                And rows >=100000
       )AS numberofrows
FROM   db_tank.sys.tables tables
WHERE  Objectproperty(tables.object_id, N‘TableHasClustIndex‘) = 0
)t where numberofrows is not null

--另外一种办法select rows,object_name(id),indid from sysindexes where indid=0 and rows>=100000

【2】查看索引相关

-------------------查看缺失索引-----------------------------------------

SELECT
  avg_total_user_cost * avg_user_impact * (user_seeks + user_scans)
    AS PossibleImprovement
  ,last_user_seek
  ,last_user_scan
  ,statement AS Object
  ,‘CREATE INDEX [IDX_‘ + CONVERT(VARCHAR,GS.Group_Handle) + ‘_‘ +
  CONVERT(VARCHAR,D.Index_Handle) + ‘_‘
    + REPLACE(REPLACE(REPLACE([statement],‘]‘,‘‘),‘[‘,‘‘),‘.‘,‘‘) +
    ‘]‘
    +‘ ON ‘
    + [statement]
    + ‘ (‘ + ISNULL (equality_columns,‘‘)
    + CASE WHEN equality_columns IS NOT NULL AND inequality_columns IS
      NOT NULL THEN ‘,‘ ELSE ‘‘ END
    + ISNULL (inequality_columns, ‘‘)
    + ‘)‘
    + ISNULL (‘ INCLUDE (‘ + included_columns + ‘)‘, ‘‘)
  AS Create_Index_Syntax
FROM
  sys.dm_db_missing_index_groups AS G
INNER JOIN
  sys.dm_db_missing_index_group_stats AS GS
ON
  GS.group_handle = G.index_group_handle
INNER JOIN
  sys.dm_db_missing_index_details AS D
ON
  G.index_handle = D.index_handle
Order By PossibleImprovement DESC

------------------缺失索引-----------------------
SELECT migs.group_handle, mid.*
FROM sys.dm_db_missing_index_group_stats AS migs
INNER JOIN sys.dm_db_missing_index_groups AS mig
ON (migs.group_handle = mig.index_group_handle)
INNER JOIN sys.dm_db_missing_index_details AS mid
ON (mig.index_handle = mid.index_handle)
WHERE migs.group_handle = 2

----------------------------------无用索引----------------------
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
DB_NAME() AS DatbaseName
, SCHEMA_NAME(O.Schema_ID) AS SchemaName
, OBJECT_NAME(I.object_id) AS TableName
, I.name AS IndexName
INTO #TempNeverUsedIndexes
FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id
WHERE 1=2
EXEC sp_MSForEachDB ‘USE [?]; INSERT INTO #TempNeverUsedIndexes
SELECT
DB_NAME() AS DatbaseName
, SCHEMA_NAME(O.Schema_ID) AS SchemaName
, OBJECT_NAME(I.object_id) AS TableName
, I.NAME AS IndexName
FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id
LEFT OUTER JOIN sys.dm_db_index_usage_stats S ON S.object_id = I.object_id
AND I.index_id = S.index_id
AND DATABASE_ID = DB_ID()
WHERE OBJECTPROPERTY(O.object_id,‘‘IsMsShipped‘‘) = 0
AND I.name IS NOT NULL
AND S.object_id IS NULL‘
SELECT * FROM #TempNeverUsedIndexes
ORDER BY DatbaseName, SchemaName, TableName, IndexName
DROP TABLE #TempNeverUsedIndexes

--------------------------经常被大量更新,但是却基本不适用的索引项--------------------
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
INTO #TempUnusedIndexes
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE 1=2
EXEC sp_MSForEachDB ‘USE [?]; INSERT INTO #TempUnusedIndexes
SELECT TOP 20
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = O.object_id
WHERE s.database_id = DB_ID()
AND OBJECTPROPERTY(s.[object_id], ‘‘IsMsShipped‘‘) = 0
AND s.user_seeks = 0
AND s.user_scans = 0
AND s.user_lookups = 0
AND i.name IS NOT NULL
ORDER BY s.user_updates DESC‘
SELECT TOP 20 * FROM #TempUnusedIndexes ORDER BY [user_updates] DESC
DROP TABLE #TempUnusedIndexes

----------------------查看未用索引----------------------------
SELECT
ind.Index_id,
obj.Name as TableName,
ind.Name as IndexName,
ind.Type_Desc,
indUsage.user_seeks,
indUsage.user_scans,
indUsage.user_lookups,
indUsage.user_updates,
indUsage.last_user_seek,
indUsage.last_user_scan,
‘drop index [‘ + ind.name + ‘] ON [‘ + obj.name + ‘]‘ as
DropIndexCommand
FROM
Sys.Indexes as ind
JOIN
Sys.Objects as obj
ON
ind.object_id=obj.Object_ID
LEFT JOIN
sys.dm_db_index_usage_stats indUsage
ON
ind.object_id = indUsage.object_id
AND
ind.Index_id=indUsage.Index_id
WHERE
ind.type_desc<>‘HEAP‘ and obj.type<>‘S‘
AND
objectproperty(obj.object_id,‘isusertable‘) = 1
AND
(isnull(indUsage.user_seeks,0) = 0
AND
isnull(indUsage.user_scans,0) = 0
AND
isnull(indUsage.user_lookups,0) = 0)
ORDER BY
obj.name,ind.Name
GO

【3】查看索引碎片

--查看索引碎片
select
db_name(database_id) as ‘数据库名‘,
object_name(t.object_id) as ‘表名‘,
t.index_id as ‘索引id‘,
t1.index_name as ‘索引名称‘,
t1.type_desc as ‘索引类型‘,
t1.column_name as ‘索引列名‘,
t.partition_number as ‘当前索引所在分区‘,
t.page_count as ‘页统计‘,
t.avg_page_space_used_in_percent as ‘页使用率‘ ,
t.record_count as ‘页行记录数‘,
t.avg_record_size_in_bytes as ‘平均每条记录大小(B)‘,
t.avg_fragmentation_in_percent as ‘索引碎片比率‘,
t.fragment_count as ‘索引中的碎片数量‘,
t.avg_fragment_size_in_pages as ‘一个索引中碎片的平均页数‘
from sys.dm_db_index_physical_stats(db_id(‘db_tank‘),NULL,NULL,NULL,NULL) t
join (select distinct t3.object_id,t3.index_id,object_name(t3.object_id) as ‘table_name‘,t3.name as ‘index_name‘,t3.type_desc, t1.name as ‘column_name‘
from sys.columns t1 join sys.index_columns t2 on t1.column_id = t2.column_id AND t1.object_id = t2.object_id
join sys.indexes t3 on t2.index_id = t3.index_id AND t2.object_id = t3.object_id) t1
on t1.object_id = t.object_id AND t1.index_id = t.index_id
where object_name(t.object_id) = ‘sys_users_goods‘

--查看所有表中对应的索引名与索引列
select t3.object_id,object_name(t3.object_id) as ‘table_name‘,t3.name as ‘index_name‘,t3.type_desc, t1.name as ‘column_name‘
from sys.columns t1 join sys.index_columns t2 on t1.column_id = t2.column_id AND t1.object_id = t2.object_id
join sys.indexes t3 on t2.index_id = t3.index_id AND t2.object_id = t3.object_id
where object_name(t3.object_id) = ‘sys_users_goods‘

--查看表中所有索引

SELECT name,type_desc FROM sys.indexes WHERE object_id=object_id(‘O_Orders‘)

--根据索引名称查看对应的列
DBCC SHOW_STATISTICS(O_Orders,idx_order_status_2)
DBCC SHOW_STATISTICS(O_Orders,IX_O_OrdersUID)

--查找碎片率大于40%的
SELECT object_name(object_id) ,index_type_desc,alloc_unit_type_desc,avg_fragmentation_in_percent,
  fragment_count,avg_fragment_size_in_pages,page_count,record_count,
  avg_page_space_used_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(‘DBNAME‘),
OBJECT_ID(‘‘),NULL,NULL,‘Sampled‘)
WHERE avg_fragmentation_in_percent>40

【3.1】在线重建DDL实践

use db_tank
go
--0、修改数据库为简单模式,以便加快效率,避免大量写日志造成频繁IO与文件过大
alter database db_tank set recovery simple
--1、declare variables

--select * from db_del..rebuild_db_tank20190513  where  索引名称=‘PK_GMActiveInfo‘
--alter index PK_GMActiveInfo on GMActiveInfo rebuild with(online=on)
--update db_del..rebuild_db_tank20190513 set flag=1 where 索引名称=‘PK_GMActiveInfo‘
--2、create table db_del..rebuild_db_tank20190513
    select
    db_name(t.database_id) as ‘数据库名‘,
    object_name(t.object_id) as ‘表名‘,
    t.index_id as ‘索引id‘,
    t1.index_name as ‘索引名称‘,
    t1.type_desc as ‘索引类型‘,
    t1.column_name as ‘索引列名‘,
    t.partition_number as ‘当前索引所在分区‘,
    t.page_count as ‘页统计‘,
    t.avg_fragmentation_in_percent as ‘索引碎片比率‘,
    t.fragment_count as ‘索引中的碎片数量‘,
    t.avg_fragment_size_in_pages as ‘一个索引中碎片的平均页数‘
    ,identity(int,1,1) rn
    ,0 as ‘flag‘
    into db_del..rebuild_db_tank20190513
    from sys.dm_db_index_physical_stats(db_id(‘db_tank‘),NULL,NULL,NULL,‘limited‘) t
    join (select distinct t3.object_id,t3.index_id,object_name(t3.object_id) as ‘table_name‘,t3.name as ‘index_name‘,t3.type_desc, t1.name as ‘column_name‘
    from sys.columns t1 join sys.index_columns t2 on t1.column_id = t2.column_id AND t1.object_id = t2.object_id
    join sys.indexes t3 on t2.index_id = t3.index_id AND t2.object_id = t3.object_id) t1
    on t1.object_id = t.object_id AND t1.index_id = t.index_id
    where t.avg_fragmentation_in_percent > 5

--update ‘text‘,‘ntext‘,‘image‘,‘xml‘,‘varchar(max)‘,‘nvarchar(max)‘,‘varbinary(max)‘,‘nvarbinary(max)‘ not online mode,the flag=2
    use db_tank
    go

    update t1
    set flag=2
    from db_del..rebuild_db_tank20190513 t1 join
    (
        select object_name(object_id) as table_name from sys.columns t1
        where t1.max_length=-1
        union
        select object_name(object_id) from sys.columns t1  join
        (select system_type_id from sys.types where name in (‘text‘,‘ntext‘,‘image‘,‘xml‘)) t2
        on t1.system_type_id=t2.system_type_id

    ) t2 on t1.[表名]=t2.table_name

declare @index_name varchar(500),@table_name varchar(500),@avg_fragment int,@flag int,@temp_index_name varchar(500)
declare @rn int ,@rn_count int
declare @sql varchar(4000),@db_name varchar(100)
--3、init
    select @rn=1,@rn_count=count(1) from db_del..rebuild_db_tank20190513
    set @temp_index_name=‘‘
--4、do_mian
    while @rn<=@rn_count
    begin
        select @index_name=[索引名称],@table_name=[表名],@avg_fragment=[索引碎片比率],@flag=flag from db_del..rebuild_db_tank20190513 where rn=@rn
        IF    @flag=0
        begin     --索引碎片率大于等于30%,则进行重建,否则进行重新整理
            IF @avg_fragment>=30
            BEGIN
                SET @sql=‘alter index ‘+@index_name+‘ on ‘+@table_name+‘ rebuild with(online=on)‘
            END
            else
            begin
                SET @sql=‘alter index ‘+@index_name+‘ on ‘+@table_name+‘ reorganize‘
            end
            print @sql
            exec(@sql)
            update db_del..rebuild_db_tank20190513 set flag=1 where [索引名称]=@index_name and [表名]=@table_name
        end
        set @rn=@rn+1

    end

--5
alter database db_tank set recovery bulk_logged    

go

原文地址:https://www.cnblogs.com/gered/p/11044571.html

时间: 2024-10-07 09:11:48

【基本优化实践】【1.2】索引优化——查看堆表、查看索引使用情况、查看索引碎片率的相关文章

数据库----问题1:数据库索引底层是怎样实现的,哪些情况下索引会失效?

什么是索引: 一个索引是存储的表中一个特定列的值数据结构(最常见的是B-Tree).索引是在表的列上创建.所以,要记住的关键点是索引包含一个表中列的值,并且这些值存储在一个数据结构中.请记住记住这一点:索引是一种数据结构 . 哈希索引的缺点: 优点:在寻找值时哈希表效率极高,如果使用哈希索引,对于比较字符串是否相等的查询能够极快的检索出的值. 缺点:哈希表是无顺的数据结构,对于很多类型的查询语句哈希索引都无能为力.比如无法查询所有小于40岁的员工.因为哈希表只适合查询键值对-也就是说查询相等的查

Mysql 索引优化分析

MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字段的意义.助你了解索引,分析索引,使用索引,从而写出更高性能的sql语句.还在等啥子?撸起袖子就是干! 案例分析 我们先简单了解一下非关系型数据库和关系型数据库的区别. MongoDB是NoSQL中的一种.NoSQL的全称是Not only SQL,非关系型数据库.它的特点是性能高,扩张性强,模式灵

mySql索引优化分析

MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字段的意义.助你了解索引,分析索引,使用索引,从而写出更高性能的sql语句.还在等啥子?撸起袖子就是干! 案例分析 我们先简单了解一下非关系型数据库和关系型数据库的区别.MongoDB是NoSQL中的一种.NoSQL的全称是Not only SQL,非关系型数据库.它的特点是性能高,扩张性强,模式灵活

Hadoop YARN:调度性能优化实践(转)

https://tech.meituan.com/2019/08/01/hadoop-yarn-scheduling-performance-optimization-practice.html 文章对性能优化的思路,如果评测性能,找到性能瓶颈,优化,优化效果评估,上线部署给出了很好的教科书式的案例,值得一看!! 背景 YARN作为Hadoop的资源管理系统,负责Hadoop集群上计算资源的管理和作业调度. 美团的YARN以社区2.7.1版本为基础构建分支.目前在YARN上支撑离线业务.实时业务

查看表扫描次数,并对比索引对表查询的作用

1.什么是表扫描 当执行SQL 语句时,可通过""评估执行计划",查看语句的执行计划.尤其是语句设计查询,会出现"表扫描"部分: 表扫描是严重影响查询时间的因素! 2.验证 (1)新建数据表BasicMsg20161204,主键为自增列,但是将聚集索引建立在(RecvTime,AA,MsgTypecode)上: (2)新建数据表BasicMsg20161104,主键为自增列,且该列为聚集索引:在RecvTime上有非聚集索引: (3)新建数据表BasicM

SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析

原文:SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析 在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index Seek))呢?是否所有情况都是如此?又该如何优化呢? 下面我们通过一些简单的例子来分析理解这些现象.下面的实验环境为SQL SERVER 2008,如果在不同版本有所区别,欢迎指正. 堆表单索引 首先我们构建我们测试需要实验环境,

利用闪回查看Oracle表历史时刻数据

利用闪回查看Oracle表历史时刻数据 1.查看表历史时刻数据 select * from tab_test AS OF TIMESTAMP to_timestamp('20140917 10:00:00','yyyymmdd hh24:mi:ss'); 2.利用flashback table恢复表到过去某一时刻 alter table tab_test enable row movement; flashback table tab_test to timestamp ('20140917 1

mysql增加远程连接用户及查看数据库表结构

一.增加远程连接用户 1.用root权限登录数据库  2.加用户:grant all privileges on *.* to ''[email protected]'192.168.1.%' identified by '222' with grant option; 其中111为账户,222为:密码    允许的远程IP段位:192.168.1.*  3.伤处远程连接用户:drop user '111'@192.168.1.%';   或  drop  user [email protect

堆表上的唯一与非唯一非聚集索引的区别

在这篇文章里,我想详细介绍下SQL Server里唯一与非唯一非聚集索引的区别.看这个文章前,希望你已经理解了聚集和非聚集索引的概念,还有在SQL Server里是如何使用的. 很多人对唯一和非唯一索引非聚集索引的认识都不是很清晰.事实上,SQL Server在存储上这2类索引有着本质的区别,这些区别会影响到索引占用空间的大小和索引的使用效率. 今天我们从SQL Server里的堆表(Heap table) ,它是没有聚集索引定义的表,在它建立唯一和非唯一非聚集索引,来开始我们的分析.下列脚本会