Улучшает ли внешний ключ производительность запросов?

149

Предположим, у меня есть 2 таблицы, продукты и категории продуктов. Обе таблицы имеют отношение к CategoryId. И это запрос.

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category
FROM Products p
INNER JOIN ProductCategories c ON p.CategoryId = c.CategoryId
WHERE c.CategoryId = 1;

Когда я создаю план выполнения, таблица ProductCategories выполняет поиск по кластерному индексу, как и ожидалось. Но для табличных продуктов он выполняет сканирование индекса кластера, что вызывает у меня сомнения. Почему FK не помогает улучшить производительность запросов?

Поэтому я должен создать индекс для Products.CategoryId. Когда я снова создаю план выполнения, обе таблицы выполняют поиск по индексу. И оценочная стоимость поддерева значительно снижается.

Мои вопросы:

  1. Помимо FK помогает в ограничении отношений, есть ли у него какая-либо другая полезность? Улучшает ли это производительность запросов?

  2. Должен ли я создать индекс для всех столбцов FK (понравился Products.CategoryId) во всех таблицах?

Chaowlert Chaisrichalermpol
источник

Ответы:

186

Внешние ключи - это инструмент ссылочной целостности, а не инструмент производительности. По крайней мере в SQL Server создание FK не создает связанный индекс, и вы должны создавать индексы для всех полей FK, чтобы улучшить время поиска.

cmsjr
источник
40
Хорошие модели (как правило) работают лучше.
Кенни Эвитт
10
«Внешние ключи - это инструмент реляционной целостности» - пожалуйста, используйте слово «реляционный» с осторожностью. Внешние ключи - это концепция базы данных, сокращение для ограничения ссылочной целостности. Они не являются частью реляционной модели. Я полагаю, вы сделали опечатку.
onedaywhen
7
@ Кенни Часто да, но иногда лучшая модель стоит дороже. Пример: внешние ключи вызывают больше обработки, а не меньше.
Ганс
8
внешние ключи делают повышение производительности, по крайней мере , в MySQL. Более того, вы правы, создание FK не создает индекса; создание ФК требует индекса
Феликс Ганьон-Гренье
15
Этот ответ в значительной степени бесполезен, потому что он не отвечает на вопрос. Приятно знать, что внешние ключи не предназначены для (положительного) влияния на производительность, но вопрос касался реальности, а не намерений.
Джон
58

Иностранные ключи могут улучшить (и ухудшить) производительность

  1. Как указано здесь: внешние ключи повышают производительность

  2. Вы должны всегда создавать индексы для столбцов FK, чтобы уменьшить количество просмотров. SQL Server не делает это автоматически.

редактировать

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

Может ли внешний ключ улучшить производительность

Ограничение по внешнему ключу повышает производительность во время чтения данных, но в то же время снижает производительность во время вставки / изменения / удаления данных.

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

Ливен Керсмакерс
источник
3
Вот ссылка, в которой подробно описываются способы снижения
cmsjr
3
Это имеет смысл, но вы столкнетесь с этим только с помощью массивного оператора delete. Возможно, следует сделать вывод, что в средах OLAP неиндексированные FK улучшат производительность, а в средах OLTP - снизят производительность.
Ливен Керсмакерс
1
Ссылка в этом ответе мертва. Это вызывает сожаление, поскольку это единственный аргумент в пользу улучшения производительности FK.
Крис Москини
1
@ChrisMoschini - я не заметил твой комментарий до сих пор. Как вы упомянули, ссылка устарела, но суть ее упоминается в новой ссылке (с подробностями), которую я разместил.
Ливен Керсмейкерс
2
Wayback Machine ссылка для Win! Статью также можно найти на сайте SQLMag.com здесь .
Джон Эйсбренер,
15

Внешний ключ - это концепция СУБД для обеспечения целостности базы данных.

Любые последствия / улучшения производительности будут зависеть от используемой технологии базы данных и будут вторичными по отношению к назначению внешнего ключа.

В SQL Server рекомендуется, чтобы на всех внешних ключах был хотя бы некластеризованный индекс.

Я надеюсь, что это прояснит ситуацию для вас, но вы можете запросить более подробную информацию.

Джон Сансом
источник
9
@ Кенни Эвитт, если у вас нет целостности, ваши данные бесполезны. Я считаю, что продается очень легко.
HLGEM
@HLGEM Время от времени получая ошибку 404, все еще терпимо. Имея исключительную пропускную способность взамен, используя более дешевые ресурсы и менее сложные системы, теперь это тоже очень легко продается. Возможно, вас заинтересует теорема CAP .
Даниэль Динниес
8
@ Даниэль Динниес, целостность данных не связана с ошибкой 404. Речь идет о наличии полезных данных. Речь идет не о потере заказов и финансовых данных для отчетов, например, из-за некомпетентности разработчиков. Нет никаких оправданий для не использования внешних ключей.
HLGEM
2
Я согласен с HLGEM. Позволить вашему коду обрабатывать целостность не всегда хорошая идея. Данные часто используются для принятия решений, но если данные повреждены, то решение не будет точным.
Лепе
1
«Внешние ключи - это инструмент реляционной целостности» - пожалуйста, используйте слово «реляционный» с осторожностью. Внешние ключи - это концепция базы данных, сокращение для ограничения ссылочной целостности. Они не являются частью реляционной модели. Я полагаю, вы сделали опечатку.
onedaywhen
4

Ваша лучшая ставка на производительность - использовать индексы в тех областях, которые вы часто используете. Если вы используете SQL Server, вы можете использовать профилировщик для профилирования конкретной базы данных, взять файл, который выводится, и использовать мастер настройки, чтобы получить рекомендации о том, где разместить ваши индексы. Мне также нравится использовать профилировщик для очистки давно запущенных хранимых процедур, у меня есть список из десяти худших правонарушителей, который я публикую каждую неделю, чтобы люди были честными: D.

Аль Катавази
источник
3

Вы можете использовать его, чтобы сделать запрос более эффективным. Это позволяет вам реструктурировать запросы в SQL Server, чтобы использовать внешнее соединение вместо внутреннего, что устраняет необходимость проверки на серверах sql наличия нулевого значения в столбце. Вам не нужно вводить этот квалификатор, потому что отношение внешнего ключа уже сообщает вам об этом.

Итак, это:

    select p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
from Products p inner join ProductCategories c on p.CategoryId = c.CategoryIdwhere c.CategoryId = 1;

Становится так:

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
FROM ProductCategories c 
LEFT OUTER JOIN Products P ON
c.CategoryId = p.CategoryId 
WHERE c.CategoryId = 1;

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

kemiller2002
источник
3
Внешние объединения не только обычно менее эффективны, чем внутренние ( stackoverflow.com/a/2726683/155892 ), теперь ваши запросы вводят в заблуждение: вы полагаетесь на базу данных, которая неявно превращает ваши внешние объединения во внутренние объединения (восстанавливая производительность) вместо того, чтобы делать это явно
Марк Соул
2

Для MySQL 5.7 это определенно может ускорить запросы, включающие множественные объединения!

Я использовал «объяснение», чтобы понять мой запрос, и обнаружил, что я объединяю 4-5 таблиц - где ключи вообще не использовались. Я ничего не сделал, кроме добавления внешнего ключа к этим таблицам, и в результате время загрузки сократилось на 90%. Запросы, которые заняли> 5 с, теперь занимают 500 мс или меньше.

Это ОГРОМНОЕ улучшение!

И, как уже упоминалось, вы получаете дополнительный бонус за обеспечение целостности отношений.

Помимо этого, обеспечение ссылочной целостности также имеет свои преимущества в производительности. Он имеет эффект второго порядка, гарантирующий, что таблицы, имеющие внешний ключ, «соответствуют» внешней таблице. Скажем, у вас есть таблица пользователей и таблица комментариев, и вы делаете некоторую статистику по таблице комментариев. Возможно, если вы трудно удалить пользователя, вы не хотите их комментарии больше, либо.

Питер Бартлетт
источник
Были ли в таблицах необходимые индексы для генерации внешних ключей перед их добавлением?
Джордж
1

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

Панкай Хайрнар
источник
0

Я не очень разбираюсь в SQL-сервере, но в случае с Oracle наличие столбца внешнего ключа снижает производительность загрузки данных. Это потому, что база данных должна проверять целостность данных для каждой вставки. И да, как уже упоминалось, наличие индекса по столбцу внешнего ключа является хорошей практикой.

Shamik
источник