如何检查表中是否存在某个索引?


287

像这样:

SELECT
* 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS 
WHERE CONSTRAINT_NAME ='FK_TreeNodesBinaryAssets_BinaryAssets'
and TABLE_NAME = 'TreeNodesBinaryAssets'

但是对于索引。


10
我希望INFORMATION_SCHEMA实际上拥有所有模式信息
Alan Macdonald

Answers:


479

您可以使用以下简单选择来做到这一点:

SELECT * 
FROM sys.indexes 
WHERE name='YourIndexName' AND object_id = OBJECT_ID('Schema.YourTableName')

76
您也可以将语句包装到中IF EXISTS(SELECT * ...) BEGIN ... END
bounav

26
值得一提的是,YourTableName应使用架构全名
-Marek

2
@blasto如果您使用非默认架构,就像在大多数情况下一样,则必须将架构指定为前缀。在其他情况下,您将不会在此查询中获得任何结果
Marek

3
要检查临时表,可以使用'tempdb.sys.indexes'和'tempdb ..#TableName'。(ref Bjorn D. Jensen
crokusek

6
只需添加:“从SQL Server 2016开始,您可以使用DROP INDEX IF EXISTS语法。” MS文档
heringer

100

对于SQL 2008及更高版本,一种更简洁的方法(通过编码)可通过使用INDEXPROPERTY内置函数来检测索引的存在:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

最简单的用法是使用IndexID属性:

If IndexProperty(Object_Id('MyTable'), 'MyIndex', 'IndexID') Is Null

如果索引存在,则上面的将返回其ID;如果没有,它将返回NULL


71

AdaTheDEV,我使用了您的语法并创建了以下内容以及原因。

问题:由于缺少索引,流程每季度运行一次,耗时一个小时。

更正:更改查询过程或过程以检查索引并在丢失时创建索引...在查询和过程的末尾放置了相同的代码以删除索引,因为它不是必需的,而是每季度一次。在这里显示Only drop语法

-- drop the index 
begin

  IF EXISTS (SELECT *  FROM sys.indexes  WHERE name='Index_Name' 
    AND object_id = OBJECT_ID('[SchmaName].[TableName]'))
  begin
    DROP INDEX [Index_Name] ON [SchmaName].[TableName];
  end

end

15

从原来的问题略有偏差然而可能被证明为今后人们在这里登陆想要有用DROP,并CREATE在部署脚本的景气指数,即。

您只需在create语句中添加以下内容,即可绕过存在检查:

CREATE INDEX IX_IndexName
ON dbo.TableName
WITH (DROP_EXISTING = ON);

在此处阅读更多内容:CREATE INDEX(Transact-SQL)-DROP_EXISTING子句

注意:如注释中所述,索引必须已经存在,此子句才能正常运行而不会引发错误。


8
其实..要小心!如果索引不存在,这将失败!至少在SQL Server 2008中
安德烈Kaipov

1
...并且在SQL 2016中仍然失败
Magier's

2
另一个(也许很明显)的效果是它将始终重新创建索引。这可能不是您想要的。在大表上删除和创建索引是一项昂贵的操作-特别是如果现有索引已经是您想要的索引。此语句适合单步替换。它不比较现有索引,而是蛮力地“即使存在,也要这样做-丢下它……只要做就做!” :-)它仍然需要OP寻找的所有检查。但是,如果索引需要替换,它将结合DROP / CREATE。
ripvlan


7

编写了以下功能,使我可以快速检查索引是否存在;就像OBJECT_ID一样工作。

CREATE FUNCTION INDEX_OBJECT_ID (
    @tableName VARCHAR(128),
    @indexName VARCHAR(128)
    )
RETURNS INT
AS
BEGIN
    DECLARE @objectId INT

    SELECT @objectId = i.object_id
    FROM sys.indexes i
    WHERE i.object_id = OBJECT_ID(@tableName)
    AND i.name = @indexName

    RETURN @objectId
END
GO

编辑:这只是返回表的OBJECT_ID,但是如果索引不存在,它将为NULL。我想您可以将其设置为返回index_id,但这不是超级有用。


1
-- Delete index if exists
IF EXISTS(SELECT TOP 1 1 FROM sys.indexes indexes INNER JOIN sys.objects 
objects ON indexes.object_id = objects.object_id WHERE indexes.name 
='Your_Index_Name' AND objects.name = 'Your_Table_Name')
BEGIN
    PRINT 'DROP INDEX [Your_Index_Name] ON [dbo].[Your_Table_Name]'
    DROP INDEX [our_Index_Name] ON [dbo].[Your_Table_Name]
END
GO

-1

要检查特定表上是否存在聚集索引:

SELECT * FROM SYS.indexes 
WHERE index_id = 1 AND name IN (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'Table_Name')

5
这将返回主键和唯一约束,但这些都不一定是聚簇索引。
Mark Sowul 2013年

index_id = 1不正确的where子句。可以为索引分配一个不同的id
Fuzzybear
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.