【基本优化实践】【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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值