是否在SQL Server中自动索引外键?


69

以下SQL语句会自动在Table1.Table1Column上创建索引,还是必须明确创建一个索引?

数据库引擎是SQL Server 2000

       CREATE TABLE [Table1] (
. . .
            CONSTRAINT [FK_Table1_Table2] FOREIGN KEY 
            (
                [Table1Column]
            ) REFERENCES [Table2] (
                [Table2ID]
            )

        )

Answers:


61

SQL Server不会自动在外键上创建索引。同样从MSDN:

一个FOREIGN KEY约束不必只链接到另一个表中的PRIMARY KEY约束。也可以定义它引用另一个表中UNIQUE约束的列。FOREIGN KEY约束可以包含空值;但是,如果复合FOREIGN KEY约束的任何列包含空值,那么将跳过对构成FOREIGN KEY约束的所有值的验证。为确保验证复合FOREIGN KEY约束的所有值,请在所有参与列上指定NOT NULL。


所有证据似乎都指向Table1Column上没有自动索引。通常在没有SQL Server抱怨的情况下创建索引。
Karmic Coder

9
带引号的文字与问题或不自动创建索引的语句有什么关系?
约翰·

22

当我阅读Mike的问题时,他在问FK约束是否将在FK所在的表(表1)中的FK列上创建索引。答案是否定的,而且通常如此。(出于约束目的),则无需这样做。另一方面,定义为约束的“ TARGET”的列必须是被引用表中的唯一索引,即主键或备用键。(唯一索引)或“创建约束”语句将失败。

(编辑:添加为显式处理下面的注释-)特别是在提供外键约束的数据一致性时。索引仅对删除FK端的一个或多个Row会影响DRI约束的性能。使用约束时,在插入或更新期间,处理器知道FK值,并且必须在PK端的引用表中检查是否存在行。那里已经有一个索引。在PK端删除一行时,它必须验证FK端没有行。在这种情况下,索引可能会有所帮助。但这不是常见的情况。

但是,除此之外,在某些类型的查询中,查询处理器需要在使用该外键列的联接的许多端查找记录。当该外键上存在索引时,联接性能提高。但是这种条件是联接查询中FK列的使用所特有的,而不是外键约束的存在……联接的另一端是PK还是仅仅是其他任意列都没有关系。同样,如果您需要根据该FK列过滤查询或对查询结果进行排序,则索引将有所帮助...同样,这与该列上的外键约束无关。


12
“而且通常不需要这样做……”-恐怕该陈述是错误的。对FK进行索引可以在许多情况下提高性能。
米奇·

@Mike,您可能想在联接中使用同一列(索引可以提供帮助)这一事实并不意味着约束需要索引。您可能还希望在where子句谓词中使用索引,其中索引也可能会有所帮助。这是否意味着仅在DRI约束的FK端需要索引?不,约束上的FK“通常”(PK端的删除除外)不会从索引中受益。从联接中使用FK列(不同的情况),或在Where子句中使用FK列是从索引中受益的原因。
Charles Bretana 09年

2
如果外键上没有索引,则删除引用表上的行将导致使用外键对表进行表扫描。sqlperformance.com/2012/11/t-sql-queries/...
大卫Sopko

如果未索引外键,则简单地联接表将导致表扫描。例如:获取表“ Purchases”和“ PurchasedItems”。对于特定的购买,加入PurchasedItems的商品将扫描所有已购买的商品。
大卫·索普科

8

不,在列上创建外键不会自动在该列上创建索引。在以下每种情况下,未能为外键列建立索引将导致表扫描:

  • 每次从引用(父)表中删除一条记录。
  • 每次将两个表连接到外键上。
  • 每次更新FK列。

在此示例架构中:

CREATE TABLE MasterOrder (
   MasterOrderID INT PRIMARY KEY)

CREATE TABLE OrderDetail(
   OrderDetailID INT,
   MasterOrderID INT  FOREIGN KEY REFERENCES MasterOrder(MasterOrderID)
)

每当在MasterOrder表中删除一条记录时,都会扫描OrderDetail。每次您加入OrderMaster和OrderDetail时,也会扫描整个OrderDetail表。

   SELECT ..
   FROM 
      MasterOrder ord
      LEFT JOIN OrderDetail det
       ON det.MasterOrderID = ord.MasterOrderID
   WHERE ord.OrderMasterID = @OrderMasterID

通常,不为外键编制索引比规则是例外。

不索引外键的情况是永远不会使用它。这将使服务器不必要的维护费用。类型表可能会不时地属于此类别,例如:

CREATE TABLE CarType (
   CarTypeID INT PRIMARY KEY,
   CarTypeName VARCHAR(25)
)

INSERT CarType .. VALUES(1,'SEDAN')
INSERT CarType .. VALUES(2,'COUP')
INSERT CarType .. VALUES(3,'CONVERTABLE')

CREATE TABLE CarInventory (
   CarInventoryID INT,
   CarTypeID INT  FOREIGN KEY REFERENCES CarType(CarTypeID)
)

大致假设CarType.CarTypeID字段永远不会更新,删除记录几乎不会,因此,如果CarTypeID从未搜索过CarInventory,则不需要在CarInventory.CarTypeID上维护索引的服务器开销。

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.