คุณจะตรวจสอบว่ามีดัชนีอยู่ในตารางได้อย่างไร?


288

บางสิ่งเช่นนี้

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

แต่สำหรับดัชนี


11
ฉันหวังว่า Information_SCHEMA จะมีข้อมูลสคีมาทั้งหมดจริงๆ
Alan Macdonald

คำตอบ:


480

คุณสามารถทำได้โดยใช้ตัวเลือกส่งตรงดังนี้:

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

76
IF EXISTS(SELECT * ...) BEGIN ... ENDนอกจากนี้คุณยังสามารถตัดงบลงไปที่
bounav

26
เป็นมูลค่าการกล่าวถึงที่YourTableNameควรจะเป็นชื่อเต็มกับสคี
มาเร็

2
@blasto หากคุณใช้สคีมาที่ไม่ใช่ค่าเริ่มต้นเช่นในกรณีส่วนใหญ่ของฉันการระบุสคีมานั้นจำเป็นต้องมีคำนำหน้า ในกรณีอื่นคุณจะไม่ได้รับผลลัพธ์ใด ๆ ในแบบสอบถามนี้
Marek

3
ในการตรวจสอบกับตาราง temp สามารถใช้ 'tempdb.sys.indexes' และ 'tempdb .. # TableName' (ผู้อ้างอิงBjorn D. Jensen )
crokusek

7
เพียงเพิ่ม: "เริ่มต้นด้วย SQL Server 2016 คุณสามารถใช้ DROP INDEX IF EXISTS syntax" เอกสาร MS
heringer

100

สำหรับSQL 2008 และใหม่กว่าวิธีที่กระชับยิ่งกว่านั้นคือการเข้ารหัสเพื่อตรวจสอบการมีอยู่ของดัชนีโดยใช้INDEXPROPERTYฟังก์ชันในตัว:

INDEXPROPERTY ( object_ID , index_or_statistics_name , property )  

การใช้งานที่ง่ายที่สุดคือกับIndexIDคุณสมบัติ:

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

หากมีดัชนีอยู่ด้านบนจะส่งคืนรหัส NULLถ้ามันไม่ได้ก็จะกลับ


71

AdaTheDEV ฉันใช้ไวยากรณ์ของคุณและสร้างสิ่งต่อไปนี้และสาเหตุ

ปัญหา: กระบวนการทำงานไตรมาสละครั้งใช้เวลาหนึ่งชั่วโมงเนื่องจากดัชนีหายไป

การแก้ไข: แก้ไขกระบวนการค้นหาหรือกระบวนงานเพื่อตรวจสอบดัชนีและสร้างหากไม่มี ... รหัสเดียวกันจะถูกวางไว้ที่ส่วนท้ายของแบบสอบถามและขั้นตอนการลบดัชนีเนื่องจากไม่จำเป็น แต่เป็นรายไตรมาส แสดงเฉพาะการวางไวยากรณ์ที่นี่

-- 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 INDEX IX_IndexName
ON dbo.TableName
WITH (DROP_EXISTING = ON);

อ่านเพิ่มเติมได้ที่นี่: สร้างดัชนี (Transact-SQL) - DROP_EXISTING Clause

หมายเหตุดังที่ได้กล่าวไว้ในความคิดเห็นดัชนีต้องมีอยู่แล้วเพื่อให้ประโยคนี้ทำงานได้โดยไม่ผิดพลาด


8
ที่จริง .. ระวังตัวด้วย! สิ่งนี้จะล้มเหลวหากไม่มีดัชนีอยู่! อย่างน้อยใน SQL Server 2008
Andrey Kaipov

1
... และยังคงล้มเหลวใน SQL 2016
Magier

2
เอฟเฟกต์ (อาจชัดเจน) อีกอย่างคือมันจะสร้างดัชนีอีกครั้ง นี่อาจไม่ใช่สิ่งที่คุณต้องการ การดร็อปและสร้างดัชนีบนตารางขนาดใหญ่เป็นการดำเนินการที่มีราคาแพงโดยเฉพาะถ้าดัชนีที่มีอยู่นั้นเป็นดัชนีที่คุณต้องการอยู่แล้ว คำสั่งนี้เป็นสิ่งที่ดีสำหรับการเปลี่ยนหนึ่งขั้นตอน มันไม่ได้เปรียบเทียบดัชนีที่มีอยู่ - แทนที่จะเป็นเดรัจฉาน "ทำสิ่งนี้แม้ว่าจะมีอยู่แล้ว - วางมันลงไป ... ทำได้เลยทำได้เลย!" :-) มันยังคงต้องการการตรวจสอบทั้งหมดที่ OP ต้องการ อย่างไรก็ตามหากดัชนีต้องการแทนที่มันจะรวม DROP / CREATE
ripvlan

10

หากจุดประสงค์ที่ซ่อนอยู่ของคำถามของคุณคือDROPดัชนีก่อนสร้างINSERTตารางขนาดใหญ่แสดงว่าสิ่งนี้มีประโยชน์หนึ่งซับ:

DROP INDEX IF EXISTS [IndexName] ON [dbo].[TableName]

ไวยากรณ์นี้มีให้ตั้งแต่ SQL Server 2016 เอกสารสำหรับIF EXISTS:

https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/

ในกรณีที่คุณจัดการกับไพรเมอร์คีย์แทนให้ใช้สิ่งนี้:

ALTER TABLE [TableName] DROP CONSTRAINT IF EXISTS [PK_name] 

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

index_id = 1 ไม่ถูกต้องโดยที่ clause ดัชนีอาจถูกกำหนด id อื่น
Fuzzybear
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.