如何获取SQL Server 2005+中所有索引和索引列的列表?我能得到的最接近的是:
select s.name, t.name, i.name, c.name from sys.tables t inner join sys.schemas s on t.schema_id = s.schema_id inner join sys.indexes i on i.object_id = t.object_id inner join sys.index_columns ic on ic.object_id = t.object_id inner join sys.columns c on c.object_id = t.object_id and ic.column_id = c.column_id where i.index_id > 0 and i.type in (1, 2) -- clustered & nonclustered only and i.is_primary_key = 0 -- do not include PK indexes and i.is_unique_constraint = 0 -- do not include UQ and i.is_disabled = 0 and i.is_hypothetical = 0 and ic.key_ordinal > 0 order by ic.key_ordinal
这不是我想要的.
我想要的是,列出所有用户定义的索引(这意味着没有支持唯一约束和主键的索引)与所有列(按它们在索引定义中的显示方式排序)加上尽可能多的元数据.
您可以参考两个"sys"目录视图:
select * from sys.indexes
select * from sys.index_columns
这些将为您提供有关索引及其列的任何信息.
编辑:此查询非常接近您正在寻找的内容:
SELECT TableName = t.name, IndexName = ind.name, IndexId = ind.index_id, ColumnId = ic.index_column_id, ColumnName = col.name, ind.*, ic.*, col.* FROM sys.indexes ind INNER JOIN sys.index_columns ic ON ind.object_id = ic.object_id and ind.index_id = ic.index_id INNER JOIN sys.columns col ON ic.object_id = col.object_id and ic.column_id = col.column_id INNER JOIN sys.tables t ON ind.object_id = t.object_id WHERE ind.is_primary_key = 0 AND ind.is_unique = 0 AND ind.is_unique_constraint = 0 AND t.is_ms_shipped = 0 ORDER BY t.name, ind.name, ind.index_id, ic.index_column_id;
您可以使用它sp_helpindex
来查看一个表的所有索引.
EXEC sys.sp_helpindex @objname = N'User' -- nvarchar(77)
对于所有索引,您可以遍历sys.objects
以获取每个表的所有索引.
以上都没有为我完成这项工作,但这样做:
-- KDF9's concise index list for SQL Server 2005+ (see below for 2000) -- includes schemas and primary keys, in easy to read format -- with unique, clustered, and all ascending/descendings in a single column -- Needs simple manual add or delete to change maximum number of key columns -- but is easy to understand and modify, with no UDFs or complex logic -- SELECT schema_name(schema_id) as SchemaName, OBJECT_NAME(si.object_id) as TableName, si.name as IndexName, (CASE is_primary_key WHEN 1 THEN 'PK' ELSE '' END) as PK, (CASE is_unique WHEN 1 THEN '1' ELSE '0' END)+' '+ (CASE si.type WHEN 1 THEN 'C' WHEN 3 THEN 'X' ELSE 'B' END)+' '+ -- B=basic, C=Clustered, X=XML (CASE INDEXKEY_PROPERTY(si.object_id,index_id,1,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ (CASE INDEXKEY_PROPERTY(si.object_id,index_id,2,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ (CASE INDEXKEY_PROPERTY(si.object_id,index_id,3,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ (CASE INDEXKEY_PROPERTY(si.object_id,index_id,4,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ (CASE INDEXKEY_PROPERTY(si.object_id,index_id,5,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ (CASE INDEXKEY_PROPERTY(si.object_id,index_id,6,'IsDescending') WHEN 0 THEN 'A' WHEN 1 THEN 'D' ELSE '' END)+ '' as 'Type', INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,1) as Key1, INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,2) as Key2, INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,3) as Key3, INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,4) as Key4, INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,5) as Key5, INDEX_COL(schema_name(schema_id)+'.'+OBJECT_NAME(si.object_id),index_id,6) as Key6 FROM sys.indexes as si LEFT JOIN sys.objects as so on so.object_id=si.object_id WHERE index_id>0 -- omit the default heap and OBJECTPROPERTY(si.object_id,'IsMsShipped')=0 -- omit system tables and not (schema_name(schema_id)='dbo' and OBJECT_NAME(si.object_id)='sysdiagrams') -- omit sysdiagrams ORDER BY SchemaName,TableName,IndexName ------------------------------------------------------------------- -- or to generate creation scripts put a simple wrapper around that SELECT SchemaName, TableName, IndexName, (CASE pk WHEN 'PK' THEN 'ALTER '+ 'TABLE '+SchemaName+'.'+TableName+' ADD CONSTRAINT '+IndexName+' PRIMARY KEY'+ (CASE substring(Type,3,1) WHEN 'C' THEN ' CLUSTERED' ELSE '' END) ELSE 'CREATE '+ (CASE substring(Type,1,1) WHEN '1' THEN 'UNIQUE ' ELSE '' END)+ (CASE substring(Type,3,1) WHEN 'C' THEN 'CLUSTERED ' ELSE '' END)+ 'INDEX '+IndexName+' ON '+SchemaName+'.'+TableName END)+ ' ('+ (CASE WHEN Key1 is null THEN '' ELSE Key1+(CASE substring(Type,4+1,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ (CASE WHEN Key2 is null THEN '' ELSE ', '+Key2+(CASE substring(Type,4+2,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ (CASE WHEN Key3 is null THEN '' ELSE ', '+Key3+(CASE substring(Type,4+3,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ (CASE WHEN Key4 is null THEN '' ELSE ', '+Key4+(CASE substring(Type,4+4,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ (CASE WHEN Key5 is null THEN '' ELSE ', '+Key5+(CASE substring(Type,4+5,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ (CASE WHEN Key6 is null THEN '' ELSE ', '+Key6+(CASE substring(Type,4+6,1) WHEN 'D' THEN ' DESC' ELSE '' END) END)+ ')' as CreateIndex FROM ( ... ...listing SQL same as above minus the ORDER BY... ... ) as indexes ORDER BY SchemaName,TableName,IndexName ---------------------------------------------------------- -- For SQL Server 2000 the following should work -- change table names to sysindexes and sysobjects (no dots) -- change object_id => id, index_id => indid, -- change is_primary_key => (select count(constid) from sysconstraints as sc where sc.id=si.id and sc.status&15=1) -- change is_unique => INDEXPROPERTY(si.id,si.name,'IsUnique') -- change si.type => INDEXPROPERTY(si.id,si.name,'IsClustered') -- remove all references to schemas including schema name qualifiers, and the XML type -- add select where indid<255 and si.status&64=0 (to omit the text/image index and autostats)
如果您的名称包含空格,请在创建脚本中添加方括号.
当最后一个Key列全部为空时,您知道没有丢失.
像在原始请求中一样过滤出主键等是微不足道的.
注意:请注意此解决方案,因为它不区分索引列和包含列.
- 短而甜蜜:
SELECT OBJECT_SCHEMA_NAME(T.[object_id],DB_ID()) AS [Schema], T.[name] AS [table_name], I.[name] AS [index_name], AC.[name] AS [column_name], I.[type_desc], I.[is_unique], I.[data_space_id], I.[ignore_dup_key], I.[is_primary_key], I.[is_unique_constraint], I.[fill_factor], I.[is_padded], I.[is_disabled], I.[is_hypothetical], I.[allow_row_locks], I.[allow_page_locks], IC.[is_descending_key], IC.[is_included_column] FROM sys.[tables] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] AND IC.[column_id] = AC.[column_id] WHERE T.[is_ms_shipped] = 0 AND I.[type_desc] <> 'HEAP' ORDER BY T.[name], I.[index_id], IC.[key_ordinal]
以下适用于SQL Server 2014/2016以及任何Microsoft Azure SQL数据库.
生成一个可以轻松导出到记事本/ Excel以进行切片和切块的综合结果集
表名
索引名称
索引说明
索引列 - 按顺序排列
包含的列 - 按顺序
SELECT '[' + s.NAME + '].[' + o.NAME + ']' AS 'table_name' ,+ i.NAME AS 'index_name' ,LOWER(i.type_desc) + CASE WHEN i.is_unique = 1 THEN ', unique' ELSE '' END + CASE WHEN i.is_primary_key = 1 THEN ', primary key' ELSE '' END AS 'index_description' ,STUFF(( SELECT ', [' + sc.NAME + ']' AS "text()" FROM syscolumns AS sc INNER JOIN sys.index_columns AS ic ON ic.object_id = sc.id AND ic.column_id = sc.colid WHERE sc.id = so.object_id AND ic.index_id = i1.indid AND ic.is_included_column = 0 ORDER BY key_ordinal FOR XML PATH('') ), 1, 2, '') AS 'indexed_columns' ,STUFF(( SELECT ', [' + sc.NAME + ']' AS "text()" FROM syscolumns AS sc INNER JOIN sys.index_columns AS ic ON ic.object_id = sc.id AND ic.column_id = sc.colid WHERE sc.id = so.object_id AND ic.index_id = i1.indid AND ic.is_included_column = 1 FOR XML PATH('') ), 1, 2, '') AS 'included_columns' FROM sysindexes AS i1 INNER JOIN sys.indexes AS i ON i.object_id = i1.id AND i.index_id = i1.indid INNER JOIN sysobjects AS o ON o.id = i1.id INNER JOIN sys.objects AS so ON so.object_id = o.id AND is_ms_shipped = 0 INNER JOIN sys.schemas AS s ON s.schema_id = so.schema_id WHERE so.type = 'U' AND i1.indid < 255 AND i1.STATUS & 64 = 0 --index with duplicates AND i1.STATUS & 8388608 = 0 --auto created index AND i1.STATUS & 16777216 = 0 --stats no recompute AND i.type_desc <> 'heap' AND so.NAME <> 'sysdiagrams' ORDER BY table_name ,index_name;
嘿伙计们,我没有通过,但我在原作者发布的查询中得到了我想要的东西.
我使用它(没有条件/过滤器)我的要求,但它给出了不正确的结果
主要问题是在index_id上获得没有连接条件的交叉产品的结果
SELECT S.NAME SCHEMA_NAME,T.NAME TABLE_NAME,I.NAME INDEX_NAME,C.NAME COLUMN_NAME FROM SYS.TABLES T INNER JOIN SYS.SCHEMAS S ON T.SCHEMA_ID = S.SCHEMA_ID INNER JOIN SYS.INDEXES I ON I.OBJECT_ID = T.OBJECT_ID INNER JOIN SYS.INDEX_COLUMNS IC ON IC.OBJECT_ID = T.OBJECT_ID INNER JOIN SYS.COLUMNS C ON C.OBJECT_ID = T.OBJECT_ID **AND IC.INDEX_ID = I.INDEX_ID** AND IC.COLUMN_ID = C.COLUMN_ID WHERE 1=1 ORDER BY I.NAME,I.INDEX_ID,IC.KEY_ORDINAL
我需要获取特定索引,索引列及其包含的列.这是我使用的查询:
SELECT INX.[name] AS [Index Name] ,TBL.[name] AS [Table Name] ,DS1.[IndexColumnsNames] ,DS2.[IncludedColumnsNames] FROM [sys].[indexes] INX INNER JOIN [sys].[tables] TBL ON INX.[object_id] = TBL.[object_id] CROSS APPLY ( SELECT STUFF ( ( SELECT ' [' + CLS.[name] + ']' FROM [sys].[index_columns] INXCLS INNER JOIN [sys].[columns] CLS ON INXCLS.[object_id] = CLS.[object_id] AND INXCLS.[column_id] = CLS.[column_id] WHERE INX.[object_id] = INXCLS.[object_id] AND INX.[index_id] = INXCLS.[index_id] AND INXCLS.[is_included_column] = 0 FOR XML PATH('') ) ,1 ,1 ,'' ) ) DS1 ([IndexColumnsNames]) CROSS APPLY ( SELECT STUFF ( ( SELECT ' [' + CLS.[name] + ']' FROM [sys].[index_columns] INXCLS INNER JOIN [sys].[columns] CLS ON INXCLS.[object_id] = CLS.[object_id] AND INXCLS.[column_id] = CLS.[column_id] WHERE INX.[object_id] = INXCLS.[object_id] AND INX.[index_id] = INXCLS.[index_id] AND INXCLS.[is_included_column] = 1 FOR XML PATH('') ) ,1 ,1 ,'' ) ) DS2 ([IncludedColumnsNames])
以下给出了与sp_helpindex tablename类似的内容
select T.name as TableName, I.name as IndexName, AC.Name as ColumnName, I.type_desc as IndexType from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id] inner join sys.index_columns as IC on IC.[object_id] = I.[object_id] and IC.[index_id] = I.[index_id] inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id] order by T.name, I.name
根据接受的答案和其他两个问题1,2我已经组建了以下查询:
SELECT QUOTENAME(t.name) AS TableName, QUOTENAME(i.name) AS IndexName, i.is_primary_key, i.is_unique, i.is_unique_constraint, STUFF(REPLACE(REPLACE(( SELECT QUOTENAME(c.name) + CASE WHEN ic.is_descending_key = 1 THEN ' DESC' ELSE '' END AS [data()] FROM sys.index_columns AS ic INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 0 ORDER BY ic.key_ordinal FOR XML PATH ), '', ', '), '
', ''), 1, 2, '') AS KeyColumns, STUFF(REPLACE(REPLACE(( SELECT QUOTENAME(c.name) AS [data()] FROM sys.index_columns AS ic INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id AND ic.is_included_column = 1 ORDER BY ic.index_column_id FOR XML PATH ), '', ', '), '
', ''), 1, 2, '') AS IncludedColumns, u.user_seeks, u.user_scans, u.user_lookups, u.user_updates FROM sys.tables AS t INNER JOIN sys.indexes AS i ON t.object_id = i.object_id LEFT JOIN sys.dm_db_index_usage_stats AS u ON i.object_id = u.object_id AND i.index_id = u.index_id WHERE t.is_ms_shipped = 0 AND i.type <> 0
此查询返回下面的结果,其中显示了索引列表,列和用法.非常有助于确定哪个索引的表现优于其他索引:
这将工作:
DECLARE @IndexInfo TABLE (index_name varchar(250) ,index_description varchar(250) ,index_keys varchar(250) ) INSERT INTO @IndexInfo exec sp_msforeachtable 'sp_helpindex ''?''' select * from @IndexInfo
这不会重新生成表名,您将收到没有索引的所有表的警告,如果这是一个问题,您可以在具有如下索引的表上创建一个循环:
DECLARE @IndexInfoTemp TABLE (index_name varchar(250) ,index_description varchar(250) ,index_keys varchar(250) ) DECLARE @IndexInfo TABLE (table_name sysname ,index_name varchar(250) ,index_description varchar(250) ,index_keys varchar(250) ) DECLARE @Tables Table (RowID int not null identity(1,1) ,TableName sysname ) DECLARE @MaxRow int DECLARE @CurrentRow int DECLARE @CurrentTable sysname INSERT INTO @Tables SELECT DISTINCT t.name FROM sys.indexes i INNER JOIN sys.tables t ON i.object_id = t.object_id WHERE i.Name IS NOT NULL SELECT @MaxRow=@@ROWCOUNT,@CurrentRow=1 WHILE @CurrentRow<=@MaxRow BEGIN SELECT @CurrentTable=TableName FROM @Tables WHERE RowID=@CurrentRow INSERT INTO @IndexInfoTemp exec sp_helpindex @CurrentTable INSERT INTO @IndexInfo (table_name , index_name , index_description , index_keys) SELECT @CurrentTable , index_name , index_description , index_keys FROM @IndexInfoTemp DELETE FROM @IndexInfoTemp SET @CurrentRow=@CurrentRow+1 END --WHILE SELECT * from @IndexInfo
编辑
如果你想,你可以过滤数据,这里有一些例子(这些适用于任何一种方法):
SELECT * FROM @IndexInfo WHERE index_description NOT LIKE '%primary key%' SELECT * FROM @IndexInfo WHERE index_description NOT LIKE '%nonclustered%' AND index_description LIKE '%clustered%' SELECT * FROM @IndexInfo WHERE index_description LIKE '%unique%'
with connect(schema_name,table_name,index_name,index_column_id,column_name) as ( select s.name schema_name, t.name table_name, i.name index_name, index_column_id, cast(c.name as varchar(max)) column_name from sys.tables t inner join sys.schemas s on t.schema_id = s.schema_id inner join sys.indexes i on i.object_id = t.object_id inner join sys.index_columns ic on ic.object_id = t.object_id and ic.index_id=i.index_id inner join sys.columns c on c.object_id = t.object_id and ic.column_id = c.column_id where index_column_id=1 union all select s.name schema_name, t.name table_name, i.name index_name, ic.index_column_id, cast(connect.column_name + ',' + c.name as varchar(max)) column_name from sys.tables t inner join sys.schemas s on t.schema_id = s.schema_id inner join sys.indexes i on i.object_id = t.object_id inner join sys.index_columns ic on ic.object_id = t.object_id and ic.index_id=i.index_id inner join sys.columns c on c.object_id = t.object_id and ic.column_id = c.column_id join connect on connect.index_column_id+1 = ic.index_column_id and connect.schema_name = s.name and connect.table_name = t.name and connect.index_name = i.name) select connect.schema_name,connect.table_name,connect.index_name,connect.column_name from connect join (select schema_name,table_name,index_name,MAX(index_column_id) index_column_id from connect group by schema_name,table_name,index_name) mx on connect.schema_name = mx.schema_name and connect.table_name = mx.table_name and connect.index_name = mx.index_name and connect.index_column_id = mx.index_column_id order by 1,2,3
这是备份索引的一种方法。您可以使用SHOWCONTIG评估碎片。它将列出数据库或表的所有索引以及统计信息。我会警告说,在大型数据库上,它可能会长期运行。对我来说,这种方法的好处之一是您不必成为管理员即可使用它。
-显示数据库中所有索引的碎片信息
SET NOCOUNT ON USE pubs DBCC SHOWCONTIG WITH ALL_INDEXES GO
...完成后将NOCOUNT重新关闭
-显示表上所有索引的碎片信息
SET NOCOUNT ON USE pubs DBCC SHOWCONTIG (authors) WITH ALL_INDEXES GO
-在特定索引上显示碎片信息
SET NOCOUNT ON USE pubs DBCC SHOWCONTIG (authors,aunmind) GO