Индексируются ли внешние ключи автоматически в SQL Server?

Будет ли следующий оператор SQL автоматически создавать индекс для таблицы Table1.Table1Column или его необходимо создавать явно?

Ядром базы данных является SQL Server 2000.

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

        )

person Karmic Coder    schedule 10.11.2008    source источник


Ответы (3)


SQL Server не будет автоматически создавать индекс по внешнему ключу. Также из MSDN:

Ограничение FOREIGN KEY не обязательно должно быть связано только с ограничением PRIMARY KEY в другой таблице; его также можно определить для ссылки на столбцы ограничения UNIQUE в другой таблице. Ограничение FOREIGN KEY может содержать нулевые значения; однако, если какой-либо столбец составного ограничения FOREIGN KEY содержит нулевые значения, проверка всех значений, составляющих ограничение FOREIGN KEY, пропускается. Чтобы убедиться, что все значения составного ограничения FOREIGN KEY проверены, укажите NOT NULL во всех участвующих столбцах.

person jons911    schedule 10.11.2008
comment
Все доказательства, кажется, указывают на отсутствие автоматического индекса для Table1Column. Создал индекс нормально, без жалоб SQL Server. - person Karmic Coder; 11.11.2008
comment
Какое отношение цитируемый текст имеет к вопросу или тому утверждению, что индексы не создаются автоматически? - person John; 04.07.2017

Когда я прочитал вопрос Майка, он спрашивает, создаст ли ограничение FK индекс для столбца FK в таблице, в которой находится FK (Table1). Ответ нет, и вообще. (для целей ограничения) в этом нет необходимости. Столбцы, определенные как «ЦЕЛЬ» ограничения, с другой стороны, должны быть уникальным индексом в ссылочной таблице, либо первичным ключом или альтернативный ключ. (уникальный индекс) или статус Create Constraint завершится ошибкой.

(EDIT: добавлено, чтобы явно иметь дело с комментарием ниже -) В частности, при обеспечении согласованности данных, для которой существует ограничение внешнего ключа. индекс может повлиять на производительность ограничения DRI только для удаления строки или строк на стороне FK. При использовании ограничения во время вставки или обновления процессор знает значение FK и должен проверить наличие строки в таблице, на которую ссылаются, на стороне PK. Там уже есть указатель. При удалении строки на стороне PK необходимо убедиться, что на стороне FK нет строк. Индекс может быть немного полезен в этом случае. Но это не обычный сценарий.

Однако в некоторых типах запросов обработчику запросов необходимо найти записи на множественной стороне соединения, которое использует этот столбец внешнего ключа. производительность соединения увеличивается, если для этого внешнего ключа существует индекс. Но это условие характерно для использования столбца FK в запросе на соединение, а не для существования ограничения внешнего ключа... Не имеет значения, является ли другая сторона соединения PK или просто каким-то другим произвольным столбцом. Кроме того, если вам нужно отфильтровать или упорядочить результаты запроса на основе этого столбца FK, поможет индекс... Опять же, это не имеет ничего общего с ограничением внешнего ключа для этого столбца.

person Charles Bretana    schedule 10.11.2008
comment
да и вообще в этом нет необходимости... - боюсь, это утверждение неверно. Индексирование FK может привести к повышению производительности во многих ситуациях. - person Mitch Wheat; 24.11.2009
comment
@Mike, тот факт, что вы можете использовать один и тот же столбец в объединении (где может помочь индекс), не означает, что индекс требуется для ограничения. Вы также можете использовать индекс в предикате предложения where, где индекс также может помочь. Означает ли это, что индекс требуется только для стороны FK ограничения DRI? Нет, FK в ограничении обычно (за исключением удаления на стороне PK) не получает никакой пользы от индекса. Использование столбцов FK в соединении (другая ситуация) или, если уж на то пошло, в предложении Where — это то, что приносит пользу от индекса. - person Charles Bretana; 24.11.2009
comment
Если по внешнему ключу нет индекса, то удаление строк в таблице, на которую ссылаются, приведет к сканированию таблицы по внешнему ключу. sqlperformance.com/2012/11/t-sql- запросы/ - person David Sopko; 25.11.2015
comment
Простое объединение таблиц приведет к сканированию таблицы, если внешний ключ не проиндексирован. Например: возьмем таблицы «Покупки» и «Купленные товары». Для конкретной покупки присоединение к PurchasedItems будет сканировать каждый когда-либо купленный предмет. - person David Sopko; 14.03.2019

Нет, создание внешнего ключа для столбца не приводит к автоматическому созданию индекса для этого столбца. Неспособность проиндексировать столбец внешнего ключа приведет к сканированию таблицы в каждой из следующих ситуаций:

  • Каждый раз, когда запись удаляется из указанной (родительской) таблицы.
  • Каждый раз, когда две таблицы соединяются по внешнему ключу.
  • Каждый раз столбец FK обновляется.

В этой примерной схеме:

CREATE TABLE MasterOrder (
   MasterOrderID INT PRIMARY KEY)

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

OrderDetail будет сканироваться каждый раз при удалении записи в таблице MasterOrder. Вся таблица OrderDetail также будет сканироваться каждый раз, когда вы присоединяетесь к OrderMaster и 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 никогда не будет обновляться, а удаление записей почти никогда не произойдет, накладные расходы сервера на поддержание индекса в CarInventory.CarTypeID будут излишними, если CarInventory никогда не будет искаться по CarTypeID.

person David Sopko    schedule 24.11.2015