Sqlserver自動查詢缺失索引及拼出建立索引的語句的指令碼
官方文件
avg_total_user_cost 可透過組中的索引減少的使用者查詢的平均成本
avg_user_impact 實現此缺失索引組後,使用者查詢可能獲得的平均百分比收益。 該值表示如果實現此缺失索引組,則查詢成本將按此百分比平均下降
user_seeks 由可能使用了組中建議索引的使用者查詢所導致的查詢次數
user_scans 由可能使用了組中建議索引的使用者查詢所導致的掃描次數
(migs.avg_total_user_cost * (migs.avg_user_impact / 100.0)) * (migs.user_seeks + migs.user_scans) > 100000
平均成本×平均收益×訪問次數,如果一個表的索引平均成本×平均收益是3左右,但是自上次查詢日期和時間以來該表索引的查詢seek次數就達到8萬次(還沒有包括掃描scan的次數的情況下),那麼這個計算數值還是遠遠大於10萬,這種情況下,這個表的就算已經建立了索引還是會提示繼續建立索引,這種情況下就需要在語句中排除該表的這個索引或直接排除該表
SELECT
mig.index_handle,
mid.database_id,
mid.object_id,
mid.[statement] [object_fullname],
(migs.avg_total_user_cost * (migs.avg_user_impact / 100.0)) * (migs.user_seeks + migs.user_scans) AS improvement_measure,
'CREATE INDEX [' AS [create_index_part1],
'missing_index_' + CONVERT(varchar, mig.index_group_handle) + '_' + CONVERT(varchar, mid.index_handle) + '_' + LEFT(PARSENAME(mid.statement, 1), 32) AS [create_index_name],
']' +
' ON ' + mid.statement + ' (' + ISNULL(mid.equality_columns, '') +
CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END + ISNULL(mid.inequality_columns, '') +
')' + ISNULL(' INCLUDE (' + mid.included_columns + ')', '') + ' WITH (' AS [create_index_part2],
'DATA_COMPRESSION = ROW, AS [create_index_part3],
migs.group_handle,
migs.unique_compiles,
migs.user_seeks,
migs.user_scans,
migs.last_user_seek,
migs.last_user_scan,
migs.avg_total_user_cost,
migs.avg_user_impact,
migs.system_seeks,
migs.system_scans,
migs.last_system_seek,
migs.last_system_scan,
migs.avg_total_system_cost,
migs.avg_system_impact
INTO #CINDEXES
FROM sys.dm_db_missing_index_groups AS mig
INNER JOIN sys.dm_db_missing_index_group_stats AS migs
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.avg_total_user_cost * (migs.avg_user_impact / 100.0)) * (migs.user_seeks + migs.user_scans) > 100000)
--and mid.object_id<>1771153355 排除某張表的時候,加上某張表的id就行
ORDER BY (migs.avg_total_user_cost * migs.avg_user_impact) * (migs.user_seeks + migs.user_scans) DESC
--## CHECK IF RECORDS EXIST ##
IF NOT EXISTS (SELECT TOP 1 1 FROM #CINDEXES)
BEGIN
DROP TABLE #CINDEXES
RETURN
END
--## CHECK IF INDEX ALREADY EXISTS ##
CREATE TABLE #RINDEXES (
index_handle INT NOT NULL,
sql_statement NVARCHAR(MAX) NULL
)
DECLARE @TSQL NVARCHAR(MAX)
DECLARE RunPerIndex CURSOR FOR
SELECT
index_handle,
database_id,
object_id,
improvement_measure,
object_fullname
FROM #CINDEXES
DECLARE @Handle INT,
@DatabaseID INT,
@ObjectID INT,
@Impact INT,
@ObjectFullName SYSNAME,
@Rebuild BIT,
@Filegroup SYSNAME,
@IndexName SYSNAME
OPEN RunPerIndex
FETCH NEXT FROM RunPerIndex INTO @Handle, @DatabaseID, @ObjectID, @Impact, @ObjectFullName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @TSQL =
'SET @Rebuild = 0
SET @Filegroup = NULL
SET @IndexName = NULL
DECLARE @Missing TABLE (
key_ordinal INT IDENTITY(1,1) NOT NULL,
column_id INT NOT NULL,
column_name SYSNAME NULL,
column_usage NVARCHAR(32) NULL
)
INSERT INTO @Missing
SELECT *
FROM sys.dm_db_missing_index_columns(' + CONVERT(NVARCHAR(32), @Handle) + ')
DECLARE @Count INT = @@ROWCOUNT
SELECT TOP 1
@Rebuild = 1,
@Filegroup = [filegroup],
@IndexName = [index_name]
FROM
(
SELECT
O.name [object_name], I.index_id, I.name [index_name], F.name [filegroup], COUNT(C.column_id) [index_cols], COUNT(M.column_id) [missing_cols]
FROM ' + QUOTENAME(DB_NAME(@DatabaseID)) + '.sys.index_columns IC
INNER JOIN ' + QUOTENAME(DB_NAME(@DatabaseID)) + '.sys.objects O
ON O.object_id = IC.object_id
INNER JOIN ' + QUOTENAME(DB_NAME(@DatabaseID)) + '.sys.indexes I
ON I.index_id = IC.index_id AND
I.object_id = IC.object_id
INNER JOIN ' + QUOTENAME(DB_NAME(@DatabaseID)) + '.sys.columns C
ON C.object_id = IC.object_id AND
C.column_id = IC.column_id
INNER JOIN ' + QUOTENAME(DB_NAME(@DatabaseID)) + '.sys.filegroups F
ON F.data_space_id = I.data_space_id
LEFT OUTER JOIN @Missing M
ON M.column_id = IC.column_id AND
( M.column_usage = ''INCLUDE'' OR M.key_ordinal = IC.key_ordinal ) AND
IC.is_included_column =
CASE M.column_usage
WHEN ''INCLUDE'' THEN 1
ELSE 0
END
WHERE IC.object_id = ' + CONVERT(NVARCHAR(32), @ObjectID) + '
GROUP BY O.name, I.index_id, I.name, F.name
) T
WHERE
T.index_cols = T.missing_cols AND
T.index_cols = @Count'
EXECUTE sys.sp_executesql
@TSQL,
N'@Rebuild BIT OUT, @Filegroup SYSNAME OUT, @IndexName SYSNAME OUT',
@Rebuild = @Rebuild OUT,
@Filegroup = @Filegroup OUT,
@IndexName = @IndexName OUT
IF @Rebuild = 1
BEGIN
INSERT INTO #RINDEXES
VALUES (
@Handle,
(
SELECT TOP 1
create_index_part1 + @IndexName + create_index_part2 + 'DROP_EXISTING = ON, ' + create_index_part3 + ' ON ' + QUOTENAME(@Filegroup)
FROM #CINDEXES
WHERE index_handle = @Handle
)
)
DELETE FROM #CINDEXES
WHERE index_handle = @Handle
END
FETCH NEXT FROM RunPerIndex INTO @Handle, @DatabaseID, @ObjectID, @Impact, @ObjectFullName
END
CLOSE RunPerIndex
DEALLOCATE RunPerIndex
--## SEND EMAIL ##
DECLARE @Recipients VARCHAR(510) = 'dba@net.com;',
@Subject VARCHAR(255) = UPPER(@@SERVERNAME) + ' Indexes',
@Body VARCHAR(MAX),
@RowColor BIT = 0
SET @Body =
'<style type="text/css">body { font-family:"arial"; }</style>
<body>
The following indexes need to be CREATED on ' + UPPER(@@SERVERNAME) + ': <br /><br />
<table border="1" cellspacing="0" cellpadding="10" style="text-align:center">
<thead>
<tr style="background-color:#525252; color:White">
<th>Create Statement</th>
</tr>
</thead>
<tbody>
'
SELECT
@RowColor =
CASE @RowColor
WHEN 0 THEN 1
ELSE 0
END,
@Body +=
'<tr' + CASE @RowColor WHEN 1 THEN ' style="background-color:#D3D3D3"' ELSE '' END + '>' + CHAR(13) +
'<td>' + create_index_part1 + create_index_name + create_index_part2 + create_index_part3 + '</td>' + CHAR(13) +
'</tr>' + CHAR(13)
FROM #CINDEXES
ORDER BY improvement_measure DESC
SET @Body +=
' <tbody>
</table>
<br />
<br />
The following indexes need to be REBUILT on ' + UPPER(@@SERVERNAME) + ': <br /><br />
<table border="1" cellspacing="0" cellpadding="10" style="text-align:center">
<thead>
<tr style="background-color:#525252; color:White">
<th>Rebuild Statement</th>
</tr>
</thead>
<tbody>
'
SET @RowColor = 0
SELECT
@RowColor =
CASE @RowColor
WHEN 0 THEN 1
ELSE 0
END,
@Body +=
'<tr' + CASE @RowColor WHEN 1 THEN ' style="background-color:#D3D3D3"' ELSE '' END + '>' + CHAR(13) +
'<td>' + sql_statement + '</td>' + CHAR(13) +
'</tr>' + CHAR(13)
FROM #RINDEXES
SET @Body +=
'</table>
</body>'
EXECUTE msdb.dbo.sp_send_dbmail
@recipients = @Recipients,
@profile_name = 'WON Notification',
@body_format = 'html',
@subject = @Subject,
@body = @Body;
DROP TABLE #CINDEXES
DROP TABLE #RINDEXES
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30126024/viewspace-2760795/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ElasticSearch分片互動過程(建立索引、刪除索引、查詢索引)Elasticsearch索引
- 《MySQL慢查詢優化》之SQL語句及索引優化MySql優化索引
- SQLServer查詢哪些索引利用率低SQLServer索引
- AppBoxFuture: 二級索引及索引掃描查詢資料APP索引
- 阿里面試題: (a,b,c)組合索引, 查詢語句select...from...where a=.. and c=..走索引嗎?阿里面試題索引
- 筆記 mongo查詢慢日誌,建立索引筆記Go索引
- MySQL 索引及查詢優化總結MySql索引優化
- 為什麼 SQL 語句使用了索引,但卻還是慢查詢?SQL索引
- 什麼情況下需要建立索引? 索引的作用?為什麼能夠提高查詢速度?(索引的原理) 索引有什麼副作用嗎?索引
- Elasticsearch(三):索引查詢Elasticsearch索引
- elasticsearch之多索引查詢Elasticsearch索引
- MySQ索引操作命令總結(建立、重建、查詢和刪除索引命令詳解)索引
- MySQL索引原理及慢查詢最佳化MySql索引
- 聯合索引和多個單列索引使用中的索引命中情況及索引建立原則索引
- Sqlserver查詢alwayson同步情況指令碼(2)SQLServer指令碼
- 一個查詢不走索引的例子索引
- LOB欄位相關概念(自動建立LOB索引段和重建索引方法)索引
- elasticsearch 索引清理指令碼及常用命令Elasticsearch索引指令碼
- [20180926]查詢相似索引.txt索引
- MongoDB慢查詢與索引MongoDB索引
- SQLServer索引優化(2):對於索引中include的理解SQLServer索引優化
- create table 使用select查詢語句建立表的方法分享
- [20231204]建立監測索引ind_m.sql指令碼.txt索引SQL指令碼
- TableStore多元索引,大資料查詢的利器索引大資料
- SQLServer索引優化(3):對於建組合索引的要求SQLServer索引優化
- 一文讀懂MySQL的索引結構及查詢優化MySql索引優化
- MySQL索引與查詢優化MySql索引優化
- IndexPatternService 模糊查詢索引 fuzzyQuery分析Index索引
- MySQL 的索引型別及如何建立維護MySql索引型別
- 查詢Oracle正在執行的sql語句及執行該語句的使用者OracleSQL
- 「懶惰的美德」我用 python 寫了個自動生成給文件生成索引的指令碼Python索引指令碼
- MySQL的簡單查詢語句MySql
- mysql dba常用的查詢語句MySql
- (1)掌握SqlServer索引的基本概念SQLServer索引
- sqlserver索引重建和索引重組的區別和操作方法SQLServer索引
- mysql查詢語句MySql
- mssql sqlserver 索引專題SQLServer索引
- 談談MYSQL索引是如何提高查詢效率的MySql索引