Skip to content

Commit e1cffd4

Browse files
authored
Merge pull request #3466 from erikdarlingdata/issue_3463
Update sp_BlitzIndex.sql
2 parents dd500ba + 23de247 commit e1cffd4

1 file changed

Lines changed: 216 additions & 96 deletions

File tree

sp_BlitzIndex.sql

Lines changed: 216 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,70 +1792,179 @@ BEGIN TRY
17921792
SET @dsql=N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;'
17931793

17941794

1795-
SET @dsql = @dsql + 'WITH ColumnNamesWithDataTypes AS(SELECT id.index_handle,id.object_id,cn.IndexColumnType,STUFF((SELECT '', '' + cn_inner.ColumnName + '' '' +
1796-
N'' {'' + CASE WHEN ty.name IN ( ''varchar'', ''char'' ) THEN ty.name + ''('' + CASE WHEN co.max_length = -1 THEN ''max'' ELSE CAST(co.max_length AS VARCHAR(25)) END + '')''
1797-
WHEN ty.name IN ( ''nvarchar'', ''nchar'' ) THEN ty.name + ''('' + CASE WHEN co.max_length = -1 THEN ''max'' ELSE CAST(co.max_length / 2 AS VARCHAR(25)) END + '')''
1798-
WHEN ty.name IN ( ''decimal'', ''numeric'' ) THEN ty.name + ''('' + CAST(co.precision AS VARCHAR(25)) + '', '' + CAST(co.scale AS VARCHAR(25)) + '')''
1799-
WHEN ty.name IN ( ''datetime2'' ) THEN ty.name + ''('' + CAST(co.scale AS VARCHAR(25)) + '')''
1800-
ELSE ty.name END + ''}''
1801-
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details AS id_inner
1802-
CROSS APPLY(
1803-
SELECT LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Equality'' AS IndexColumnType
1804-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.equality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1805-
CROSS APPLY n.nodes(''x'') node(v)
1806-
UNION ALL
1807-
SELECT LTRIM(RTRIM(v.value(N''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Inequality'' AS IndexColumnType
1808-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.inequality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1809-
CROSS APPLY n.nodes(''x'') node(v)
1810-
UNION ALL
1811-
SELECT LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Included'' AS IndexColumnType
1812-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.included_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1813-
CROSS APPLY n.nodes(''x'') node(v)
1814-
)AS cn_inner'
1815-
+ /*split the string otherwise dsql cuts some of it out*/
1816-
' JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS co ON co.object_id = id_inner.object_id AND ''['' + co.name + '']'' = cn_inner.ColumnName
1817-
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.types AS ty ON ty.user_type_id = co.user_type_id
1795+
SET @dsql = @dsql + '
1796+
WITH
1797+
ColumnNamesWithDataTypes AS
1798+
(
1799+
SELECT
1800+
id.index_handle,
1801+
id.object_id,
1802+
cn.IndexColumnType,
1803+
STUFF
1804+
(
1805+
(
1806+
SELECT
1807+
'', '' +
1808+
cn_inner.ColumnName +
1809+
'' '' +
1810+
N'' {'' +
1811+
CASE
1812+
WHEN ty.name IN (''varchar'', ''char'')
1813+
THEN ty.name +
1814+
''('' +
1815+
CASE
1816+
WHEN co.max_length = -1
1817+
THEN ''max''
1818+
ELSE CAST(co.max_length AS VARCHAR(25))
1819+
END +
1820+
'')''
1821+
WHEN ty.name IN (''nvarchar'', ''nchar'')
1822+
THEN ty.name +
1823+
''('' +
1824+
CASE
1825+
WHEN co.max_length = -1
1826+
THEN ''max''
1827+
ELSE CAST(co.max_length / 2 AS VARCHAR(25))
1828+
END +
1829+
'')''
1830+
WHEN ty.name IN (''decimal'', ''numeric'')
1831+
THEN ty.name +
1832+
''('' +
1833+
CAST(co.precision AS VARCHAR(25)) +
1834+
'', '' +
1835+
CAST(co.scale AS VARCHAR(25)) +
1836+
'')''
1837+
WHEN ty.name IN (''datetime2'')
1838+
THEN ty.name +
1839+
''('' +
1840+
CAST(co.scale AS VARCHAR(25)) +
1841+
'')''
1842+
ELSE ty.name END + ''}''
1843+
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details AS id_inner
1844+
CROSS APPLY
1845+
(
1846+
SELECT
1847+
LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1848+
''Equality'' AS IndexColumnType
1849+
FROM
1850+
(
1851+
VALUES
1852+
(CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.equality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1853+
) x (n)
1854+
CROSS APPLY n.nodes(''x'') node(v)
1855+
UNION ALL
1856+
SELECT
1857+
LTRIM(RTRIM(v.value(N''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1858+
''Inequality'' AS IndexColumnType
1859+
FROM
1860+
(
1861+
VALUES
1862+
(CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.inequality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1863+
) x (n)
1864+
CROSS APPLY n.nodes(''x'') node(v)
1865+
UNION ALL
1866+
SELECT
1867+
LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1868+
''Included'' AS IndexColumnType
1869+
FROM
1870+
(
1871+
VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id_inner.included_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1872+
) x (n)
1873+
CROSS APPLY n.nodes(''x'') node(v)
1874+
) AS cn_inner
1875+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS co
1876+
ON co.object_id = id_inner.object_id
1877+
AND ''['' + co.name + '']'' = cn_inner.ColumnName
1878+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.types AS ty
1879+
ON ty.user_type_id = co.user_type_id
18181880
WHERE id_inner.index_handle = id.index_handle
1819-
AND id_inner.object_id = id.object_id
1820-
AND cn_inner.IndexColumnType = cn.IndexColumnType
1821-
FOR XML PATH('''')
1822-
),1,1,'''') AS ReplaceColumnNames
1823-
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details AS id
1824-
CROSS APPLY(
1825-
SELECT LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Equality'' AS IndexColumnType
1826-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.equality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1827-
CROSS APPLY n.nodes(''x'') node(v)
1828-
UNION ALL
1829-
SELECT LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Inequality'' AS IndexColumnType
1830-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.inequality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1831-
CROSS APPLY n.nodes(''x'') node(v)
1832-
UNION ALL
1833-
SELECT LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName, ''Included'' AS IndexColumnType
1834-
FROM (VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.included_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))) x(n)
1835-
CROSS APPLY n.nodes(''x'') node(v)
1836-
)AS cn
1837-
GROUP BY id.index_handle,id.object_id,cn.IndexColumnType
1838-
)
1839-
SELECT id.database_id, id.object_id, @i_DatabaseName, sc.[name], so.[name], id.statement , gs.avg_total_user_cost,
1840-
gs.avg_user_impact, gs.user_seeks, gs.user_scans, gs.unique_compiles, id.equality_columns, id.inequality_columns, id.included_columns,
1841-
(
1842-
SELECT ColumnNamesWithDataTypes.ReplaceColumnNames
1843-
FROM ColumnNamesWithDataTypes WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1844-
AND ColumnNamesWithDataTypes.object_id = id.object_id
1845-
AND ColumnNamesWithDataTypes.IndexColumnType = ''Equality''
1846-
) AS equality_columns_with_data_type
1847-
,(
1848-
SELECT ColumnNamesWithDataTypes.ReplaceColumnNames
1849-
FROM ColumnNamesWithDataTypes WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1850-
AND ColumnNamesWithDataTypes.object_id = id.object_id
1851-
AND ColumnNamesWithDataTypes.IndexColumnType = ''Inequality''
1852-
) AS inequality_columns_with_data_type
1853-
,(
1854-
SELECT ColumnNamesWithDataTypes.ReplaceColumnNames
1855-
FROM ColumnNamesWithDataTypes WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1856-
AND ColumnNamesWithDataTypes.object_id = id.object_id
1857-
AND ColumnNamesWithDataTypes.IndexColumnType = ''Included''
1858-
) AS included_columns_with_data_type '
1881+
AND id_inner.object_id = id.object_id
1882+
AND cn_inner.IndexColumnType = cn.IndexColumnType
1883+
FOR XML PATH('''')
1884+
),
1885+
1,
1886+
1,
1887+
''''
1888+
) AS ReplaceColumnNames
1889+
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details AS id
1890+
CROSS APPLY
1891+
(
1892+
SELECT
1893+
LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1894+
''Equality'' AS IndexColumnType
1895+
FROM
1896+
(
1897+
VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.equality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1898+
) x (n)
1899+
CROSS APPLY n.nodes(''x'') node(v)
1900+
UNION ALL
1901+
SELECT
1902+
LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1903+
''Inequality'' AS IndexColumnType
1904+
FROM
1905+
(
1906+
VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.inequality_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1907+
) x (n)
1908+
CROSS APPLY n.nodes(''x'') node(v)
1909+
UNION ALL
1910+
SELECT
1911+
LTRIM(RTRIM(v.value(''(./text())[1]'', ''varchar(max)''))) AS ColumnName,
1912+
''Included'' AS IndexColumnType
1913+
FROM
1914+
(
1915+
VALUES (CONVERT(XML, N''<x>'' + REPLACE((SELECT CAST(id.included_columns AS nvarchar(max)) FOR XML PATH('''')), N'','', N''</x><x>'') + N''</x>''))
1916+
) x (n)
1917+
CROSS APPLY n.nodes(''x'') node(v)
1918+
)AS cn
1919+
GROUP BY
1920+
id.index_handle,
1921+
id.object_id,
1922+
cn.IndexColumnType
1923+
)
1924+
SELECT
1925+
*
1926+
INTO #ColumnNamesWithDataTypes
1927+
FROM ColumnNamesWithDataTypes
1928+
OPTION(RECOMPILE);
1929+
1930+
SELECT
1931+
id.database_id,
1932+
id.object_id,
1933+
@i_DatabaseName,
1934+
sc.[name],
1935+
so.[name],
1936+
id.statement,
1937+
gs.avg_total_user_cost,
1938+
gs.avg_user_impact,
1939+
gs.user_seeks,
1940+
gs.user_scans,
1941+
gs.unique_compiles,
1942+
id.equality_columns,
1943+
id.inequality_columns,
1944+
id.included_columns,
1945+
(
1946+
SELECT
1947+
ColumnNamesWithDataTypes.ReplaceColumnNames
1948+
FROM #ColumnNamesWithDataTypes ColumnNamesWithDataTypes
1949+
WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1950+
AND ColumnNamesWithDataTypes.object_id = id.object_id
1951+
AND ColumnNamesWithDataTypes.IndexColumnType = ''Equality''
1952+
) AS equality_columns_with_data_type,
1953+
(
1954+
SELECT
1955+
ColumnNamesWithDataTypes.ReplaceColumnNames
1956+
FROM #ColumnNamesWithDataTypes ColumnNamesWithDataTypes
1957+
WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1958+
AND ColumnNamesWithDataTypes.object_id = id.object_id
1959+
AND ColumnNamesWithDataTypes.IndexColumnType = ''Inequality''
1960+
) AS inequality_columns_with_data_type,
1961+
(
1962+
SELECT ColumnNamesWithDataTypes.ReplaceColumnNames
1963+
FROM #ColumnNamesWithDataTypes ColumnNamesWithDataTypes
1964+
WHERE ColumnNamesWithDataTypes.index_handle = id.index_handle
1965+
AND ColumnNamesWithDataTypes.object_id = id.object_id
1966+
AND ColumnNamesWithDataTypes.IndexColumnType = ''Included''
1967+
) AS included_columns_with_data_type,';
18591968

18601969
/* Get the sample query plan if it's available, and if there are less than 1,000 rows in the DMV: */
18611970
IF NOT EXISTS
@@ -1865,8 +1974,9 @@ BEGIN TRY
18651974
FROM sys.all_objects AS o
18661975
WHERE o.name = 'dm_db_missing_index_group_stats_query'
18671976
)
1868-
SELECT
1869-
@dsql += N' , NULL AS sample_query_plan '
1977+
SELECT
1978+
@dsql += N'
1979+
NULL AS sample_query_plan'
18701980
ELSE
18711981
BEGIN
18721982
/* The DMV is only supposed to have 600 rows in it. If it's got more,
@@ -1877,46 +1987,56 @@ BEGIN TRY
18771987

18781988
IF @MissingIndexPlans > 1000
18791989
BEGIN
1880-
SELECT @dsql += N' , NULL AS sample_query_plan /* Over 1000 plans found, skipping */ ';
1990+
SELECT @dsql += N'
1991+
NULL AS sample_query_plan /* Over 1000 plans found, skipping */';
18811992
RAISERROR (N'Over 1000 plans found in sys.dm_db_missing_index_group_stats_query - your SQL Server is hitting a bug: https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/3085',0,1) WITH NOWAIT;
18821993
END
18831994
ELSE
18841995
SELECT
18851996
@dsql += N'
1886-
, sample_query_plan =
1887-
(
1888-
SELECT TOP (1)
1889-
p.query_plan
1890-
FROM sys.dm_db_missing_index_group_stats gs
1891-
CROSS APPLY
1892-
(
1893-
SELECT TOP (1)
1894-
s.plan_handle
1895-
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_group_stats_query q
1896-
INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_exec_query_stats s
1897-
ON q.query_plan_hash = s.query_plan_hash
1898-
WHERE gs.group_handle = q.group_handle
1899-
ORDER BY (q.user_seeks + q.user_scans) DESC, s.total_logical_reads DESC
1900-
) q2
1901-
CROSS APPLY sys.dm_exec_query_plan(q2.plan_handle) p
1902-
WHERE ig.index_group_handle = gs.group_handle
1903-
) '
1997+
sample_query_plan =
1998+
(
1999+
SELECT TOP (1)
2000+
p.query_plan
2001+
FROM sys.dm_db_missing_index_group_stats gs
2002+
CROSS APPLY
2003+
(
2004+
SELECT TOP (1)
2005+
s.plan_handle
2006+
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_group_stats_query q
2007+
INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_exec_query_stats s
2008+
ON q.query_plan_hash = s.query_plan_hash
2009+
WHERE gs.group_handle = q.group_handle
2010+
ORDER BY
2011+
(q.user_seeks + q.user_scans) DESC,
2012+
s.total_logical_reads DESC
2013+
) q2
2014+
CROSS APPLY sys.dm_exec_query_plan(q2.plan_handle) p
2015+
WHERE ig.index_group_handle = gs.group_handle
2016+
)'
19042017
END
19052018

19062019

19072020

1908-
SET @dsql = @dsql + N'FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_groups ig
1909-
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details id ON ig.index_handle = id.index_handle
1910-
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_group_stats gs ON ig.index_group_handle = gs.group_handle
1911-
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects so on
1912-
id.object_id=so.object_id
1913-
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sc on
1914-
so.schema_id=sc.schema_id
1915-
WHERE id.database_id = ' + CAST(@DatabaseID AS NVARCHAR(30)) + '
1916-
' + CASE WHEN @ObjectID IS NULL THEN N''
1917-
ELSE N'and id.object_id=' + CAST(@ObjectID AS NVARCHAR(30))
1918-
END +
1919-
N'OPTION (RECOMPILE);';
2021+
SET @dsql = @dsql + N'
2022+
FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_groups ig
2023+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_details id
2024+
ON ig.index_handle = id.index_handle
2025+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_missing_index_group_stats gs
2026+
ON ig.index_group_handle = gs.group_handle
2027+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects so
2028+
ON id.object_id=so.object_id
2029+
JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sc
2030+
ON so.schema_id=sc.schema_id
2031+
WHERE id.database_id = ' + CAST(@DatabaseID AS NVARCHAR(30)) +
2032+
CASE
2033+
WHEN @ObjectID IS NULL
2034+
THEN N''
2035+
ELSE N'
2036+
AND id.object_id = ' + CAST(@ObjectID AS NVARCHAR(30))
2037+
END +
2038+
N'
2039+
OPTION (RECOMPILE);';
19202040

19212041
IF @dsql IS NULL
19222042
RAISERROR('@dsql is null',16,1);

0 commit comments

Comments
 (0)