Почему совпадения первичного ключа / внешнего ключа не используются для объединений?


48

Насколько я мог выяснить, многие СУБД (например, mysql, postgres, mssql) используют комбинации fk и pk только для ограничения изменений в данных, но они редко используются для автоматического выбора столбцов для объединения (как в естественном объединении с именами). Почему это? Если вы уже определили связь между двумя таблицами с помощью pk / fk, почему база данных не может понять, что, если я присоединяюсь к этим таблицам, я хочу присоединить их к столбцам pk / fk?

РЕДАКТИРОВАТЬ: уточнить это немного:

Предположим, у меня есть таблица1 и таблица2. Таблица 1 имеет внешний ключ в столбце а, который ссылается на первичный ключ в таблице 2, столбец b. Теперь, если я присоединюсь к этим таблицам, мне придется сделать что-то вроде этого:

SELECT * FROM table1
JOIN table2 ON table1.a = table2.b

Тем не менее, я уже определил с помощью моих ключей, что table1.a ссылается на table2.b, поэтому мне кажется, что не должно быть сложным заставить систему СУБД автоматически использовать table1.a и table2.b в качестве столбцов соединения, такой, что можно просто использовать:

SELECT * FROM table1
AUTO JOIN table2

Однако многие СУБД, похоже, не реализуют нечто подобное.

Ответы:


32

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

Однако есть серьезный недостаток! Запросы, которые являются правильными сегодня, могут стать ошибкой завтра, просто добавив второй FK в ту же таблицу!

Позвольте мне сказать это еще раз: добавляя столбцы, запросы, которые не используют эти столбцы, могут превратиться из «правильного» в «ошибку»!

Это такой кошмар обслуживания, что любое разумное руководство по стилю запретило бы использовать эту функцию. Большинство уже запрещают select *по той же причине!

Все это будет приемлемо, если производительность будет улучшена. Однако это не так.

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

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


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

1
@HLGEM, это может быть кэшировано, а также не имеет значения для больших запросов. Преимущество заключается в том, что мы можем быть уверены, что ключи не пропущены из-за человеческой ошибки.
Pacerier

Добавление и изменение столбцов также может привести к поломке NATURAL JOIN(именно поэтому я обычно их избегаю), но я не думаю, что это само по себе должно означать, что DBMS не может реализовать автоматический способ объединения таблиц на основе внешних ключей.
Джей К

2
Много случаев? На БД с тысячами таблиц у меня есть лишь несколько случаев отношения более чем 1 между двумя таблицами. Во всяком случае, это не проблема, было бы достаточно добавить имя отношения, как AUTO JOIN mytable THROUGH myrelationэто было бы очень хорошо.
Teejay

Это то, что мы делаем в нашем собственном построителе .NET SQL, с intellisense, какInnerJoin(SRC_TABLE.rDEST_TABLE.REL_NAME_F01)
Teejay

27

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

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

    table: USA_States
    StateID
    StateName
    
    table: Shipment
    ShipmentID
    PickupStateID Foreign key
    DeliveryStateID Foreign key
    

    Возможно, вы захотите присоединиться на основе состояния погрузки. Может быть, вы хотите присоединиться к состоянию доставки. Может быть, вы хотите выполнить 2 соединения для обоих! У движка sql нет возможности узнать, что вы хотите.

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

  3. В некоторых особых случаях вы присоединяетесь к столбцам, где ни один из них не является уникальным. Поэтому присутствие PK / FK на этих столбцах невозможно.

  4. Вы можете думать , пункты 2 и 3 выше не являются релевантными , поскольку ваши вопросы о том, когда есть IS один PK / FK отношения между таблицами. Однако наличие одного PK / FK между таблицами не означает, что у вас не может быть других полей для присоединения в дополнение к PK / FK. Движок sql не знает, к каким полям вы хотите присоединиться.

  5. Допустим, у вас есть таблица "USA_States" и 5 других таблиц с FK для штатов. «Пять» таблиц также имеют несколько внешних ключей друг к другу. Должен ли механизм sql автоматически объединять «пять» таблиц с «USA_States»? Или это должно соединить "пятерку" друг с другом? Обе? Вы можете установить отношения так, чтобы sql engine входил в бесконечный цикл, пытаясь соединить вещи вместе. В этой ситуации невозможно, чтобы движок sql угадал, что вы хотите.

В итоге: PK / FK не имеет ничего общего с объединениями таблиц. Это отдельные несвязанные вещи. Это просто случайность природы, когда вы часто присоединяетесь к колонкам PK / FK.

Хотели бы вы, чтобы механизм sql угадывал, является ли это полным, левым, правым или внутренним соединением? Я так не думаю. Хотя это, возможно, было бы меньшим грехом, чем угадывание столбцов для объединения.


7
Я считаю, что внешние ключи и нормализация очень важны для объединения таблиц.

3
Ваши аргументы сохраняются, когда обычное ключевое слово JOIN всегда пытается соответствовать этому (как я сделал неправильно в своем примере, я исправлю это). Однако многие объединения могут быть получены непосредственно только из этих объединений, поэтому я не вижу причин, по которым не может быть никакого явного синтаксиса для присоединения к ним. Многие СУБД имеют естественное соединение, которое в основном делает то же самое, но с именами столбцов (= плохо). То же самое можно сделать с этим типом соединения, например, указав операцию AUTO JOIN.

5
«Это просто случайность природы, что вы часто присоединяетесь к колонкам PK / FK» - я не уверен!
onedaywhen

2
«Нормализация?» Я думаю, что мысль здесь в том, что если вы начали с 1NF relvar, а затем разложили на 6NF relvars, то есть вероятность, что а) у них будут внешние ключи при реализации, и б) их часто будут объединять в запросах.
onedaywhen

4
Я бы высказался, если бы не было «PK / FK не имеет ничего общего с соединениями таблиц».
ypercubeᵀᴹ

11

понятие «присоединяемость». Отношения r1и r2являются объединяемыми, если и только если атрибуты с одинаковыми именами имеют одинаковый тип ... эта концепция применяется не только для объединения как такового, но также и для различных других операций [таких как объединение].

SQL и реляционная теория: как написать точный код SQL по дате CJ

Стандартный SQL уже имеет такую ​​функцию, известную как NATURAL JOIN, и был реализован в MySQL.

Хотя ваше предложение не настолько достойно, оно кажется разумным. В SQL Server (в котором отсутствует поддержкаNATURAL JOIN ) я использую SQL Prompt в Management Studio: при написании INNER JOINего InteliSense предлагает ONпредложения, основанные как на общих именах атрибутов, так и на внешних ключах, и я нахожу это очень полезным. У меня нет большого желания видеть новый (стандартный) тип соединения SQL для этого.


1
Естественное соединение и объединение в общих столбцах отличается от ортогонального понятия объединения в FK-PK. (См. Мой ответ.)
philipxy

@philipxy: согласен, я не собирался подразумевать иное. (Твой ответ отличный!)
четверг, 18

9

SQL пришел первым!

Ограничения внешних ключей и внешних ключей появились позже и по сути являются оптимизацией для приложений в стиле «транзакции».

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

С тех пор реляционные базы данных прошли долгий путь, и их первичное использование в качестве постоянного уровня для транзакционных систем было совсем не то, что CODD et. все предусмотрено.

Однако орган по стандартам ANSI для всех своих противоречивых целей и политики поставщиков всегда стремился сохранить «математически доказуемые» свойства SQL.

Если вы позволите базе данных выводить свойства соединения из «скрытых» данных внешнего ключа, вы потеряете это свойство (учтите неоднозначность, если определено более одного набора внешних ключей).

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


3
Спасибо, это имело смысл для меня! Тем не менее, естественные объединения не имеют таких же проблем? Хотя естественные объединения имеют даже большие проблемы, многие СУБД поддерживают их. IMO соединение, основанное на pk / fk, было бы естественным соединением, сделанным правильно.

1
Нет разницы в том, что касается большинства механизмов баз данных между естественным соединением и явным «JOIN ... ON». Движок анализирует запрос и делает соединение как можно лучше, основываясь на различных предикатах. Использование явного соединения не заставляет использовать определенный индекс или путь доступа, его в основном поддерживают синтаксис соединения «LEFT, OUTER, INNER», который должен знать предикаты явного соединения, чтобы знать, когда вставлять «пропущенную» строку ,

6
SQL не пришел первым! Реляционная модель (которая, конечно, включала концепцию внешних ключей) была впервые изложена EFCodd в 1969 году. Как и тогда, SEQUEL не видел свет примерно до 1974 года. Его изобретатели с самого начала давали понять, что Предполагалось, что SEQUEL / SQL будет основан на ранее существовавшей реляционной модели - хотя SQL действительно не был действительно реляционным языком.
nvogel

@sqlvogel - правда! Надо было сформулировать это «SQL был реализован первым».
Джеймс Андерсон

CJ Date в «Введение в системы баз данных» (стр. 276) говорит, что Кодд изобрел концепцию внешнего ключа; не говорит, когда, но я предполагаю, что это было до первой реализации SQL.
понедельник,

7

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

  • Вы можете использовать для некоторых целей декартово произведение двух таблиц или их части.
  • Могут быть и другие поля, к которым вы можете присоединиться для других целей.
  • Если вы объединяете три или более таблиц, одна из таблиц может быть связана с двумя или более таблицами. В этом случае обычно в запросе может быть подходящим только одно из возможных отношений FK.

7

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


Отредактируйте теперь, когда вопрос был полностью переписан: описываемый вами случай будет только для очень небольшого набора запросов. Что, если к столу присоединились 12 столов? Что делать, если нет FK .... Даже если бы было соединение по умолчанию, я все равно всегда указывал бы соединение только для удобства чтения. (Я не хочу смотреть на данные, а затем пытаться выяснить, к чему присоединяются)

Некоторые инструменты запросов на самом деле выполняют автоматическое объединение, а затем позволяют удалять или редактировать объединение. Я думаю, что MS Access Query Builder делает это.

Наконец, стандарт ANSII гласит, что соединение должно быть указано. Этого достаточно, чтобы не допустить этого.


3
Извините, возможно, я не достаточно ясно. Я не говорю об индексах, я говорю об объединениях. Предположим, у меня есть table1 и table2, с fk на table1.a, который указывает на table2.b. Если я присоединюсь к этим таблицам, мне придется явно сказать, что я хочу объединить их в столбцах a и b (например, «SELECT * FROM table1 JOIN table2 ON table1.a = table2.b »), хотя я уже определил в своей базе данных Схема, что эти два связаны. Вопрос в том, почему я не могу сделать «SELECT * FROM table1 JOIN table2» и позволить СУБД автоматически выбирать столбцы соединения на основе fk / pk.

4
Особенно читаемость имела смысл для меня! Однако то, что говорится в стандарте, не совсем хороший аргумент ИМО. Многие стандарты раньше делали неправильный выбор (например, HTML).

3

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

Однако нет никаких причин, по которым инструмент разработки запросов или текстовый редактор не могут автоматически завершить объединение с помощью внешних ключей так же, как они дают вам интеллектуальный смысл по имени столбца. Вы можете отредактировать запрос, если инструмент ошибся, и сохранить полностью определенный запрос. Такой инструмент также может с пользой использовать соглашение об именовании столбцов Foreign Keys именем «родительской» таблицы и столбцами с одинаковым именем в родительской / дочерней таблице и т. Д.

(Моя жена все еще не может понять разницу между Management Studio и Sql Server и говорит о запуске sql server, когда она запускает Management Studio!)


3

Естественное объединение «автоматически» объединяет равенство общих столбцов, но вы должны писать это только в том случае, если это то, что вы хотите, основываясь на значениях таблицы и желаемом результате. Там нет «автоматически», зная, как две таблицы «должны» быть объединены или каким-либо другим образом любая таблица «должны» появиться в запросе. Нам не нужно знать ограничения для запроса. Их присутствие просто означает, что входные данные могут быть ограничены, и, следовательно, выходной может быть слишком. Вы можете определить какой-то оператор join_on_fk_to_pk, который «автоматически» присоединяется в соответствии с объявленными ограничениями; но если вы хотите, чтобы значение запроса оставалось неизменным, если изменяются только ограничения, но не значения таблиц, вам придется изменить этот запрос, чтобы не использовать новые объявленные константы.уже оставляет значение то же самое, несмотря на любые изменения ограничения .

Какие ограничения (включая PK, FK, UNIQUE & CHECK) не влияют на значения таблиц. Конечно, если значения таблиц изменятся, то ограничения могут измениться. Но если ограничения меняются, это не значит, что запросы должны меняться.

Не нужно знать ограничения для запроса. Знание об ограничениях означает, что мы можем использовать дополнительные выражения, которые без удержания ограничения не вернут тот же ответ. Например, ожидая через UNIQUE, что таблица имеет одну строку, поэтому мы можем использовать ее как скаляр. Эти запросы могут прерваться, если ограничение было принято, но не объявлено. Но объявление ограничения, которое запрос не предполагал, не может его сломать.

Есть ли эмпирическое правило для построения SQL-запроса из понятного человеку описания?


2

Причина в том, что есть ЯЗЫК, а затем есть основополагающие принципы. Язык является редким и не имеет многих функций, которые вы ожидаете увидеть на языке общего назначения. Это просто хорошая функция, которая не была добавлена ​​к языку и, вероятно, не будет. Это не мертвый язык, так что есть некоторая надежда, но я не буду оптимистичен.

Как уже отмечали другие, в некоторых реализациях используется расширение, в котором соединение (столбец) объединяет две таблицы на основе общего имени столбца, что несколько похоже. Но это не широко распространено. Обратите внимание, что это расширение отличается от SELECT * FROM employee NATURAL JOIN department;синтаксиса, который не включает способ указать, какие столбцы использовать. Также не полагайтесь на отношения между таблицами, что делает их ненадежными (естественный синтаксис соединения больше, чем расширение).

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


3
Это предполагает, что это хорошая идея, что они уже должны были это сделать. Также вероятно, что они уже рассмотрели это и решили не делать этого. Возможно, на практике это очень плохая идея: Sjoerd привел пример, когда запрос может прерваться только из-за добавления нового столбца и отношения FK. Лорд Тидус также объясняет, что внешние ключи несут ответственность, отличную от определения способов соединения ваших таблиц.

1
@JonathanHobbs: я имел в виду, что мой ответ, как правило, нейтральный. Но отказ от нейтральности. Логика Шоерда ошибочна. Изменения в таблицах уже нарушают запросы, добавление нового столбца к первичному ключу таблицы приведет либо к разрыву запросов, либо к началу возврата неправильных результатов. Это на самом деле защитит вас от этого до такой степени, что, пока поддерживается связь с таблицей, изменения столбцов можно было бы выполнить безопасно. Это, вероятно, увеличило бы использование отношений FK, поскольку это было бы полезно для чего-то другого, кроме соединений RI.Most либо на ПК, либо включают в себя Pk. Для обработки нескольких fk используйте имя столбца.
Jmoreno

1

Если предполагается, что пропущенное предложение ON следует за полями, основанными на ссылочной целостности, как бы вы сделали декартово произведение?

Редактировать: с помощью AUTO Преимущества этого - меньше набирать текст, и вам не нужно знать, как они соединяются, или помнить сложное соединение. Если отношение изменяется, оно обрабатывается автоматически, но это случается редко, за исключением ранней разработки.

Что вам нужно сделать сейчас, это решить, будут ли все ваши AUTO соединения удерживаться во время смены отношений, чтобы соответствовать цели вашего оператора выбора.


1
@JeffO: главное преимущество в том, что он выражает намерение более точно, в очень четкой декларативной форме. Объединения по именам столбцов ничего не говорят вам, кроме того факта, что некоторые из содержимого столбцов похожи на содержимое другого (но могут не относиться к тому же типу). Объединение на Fk иого, говорит вам , что это Ф.К. ссылки, не список столбцов не будет означать , что только 1 Ф.К. между таблицами, или , наоборот , что есть 1+ (рассмотрит ключ многоколоночного с более чем 1 исми , что происходит , когда Вы смешиваете столбцы c1 = fk1_c1 и c2 = fk2_c2). Даже при большем наборе в среднем это было бы хорошо.
Jmoreno

Использование (INNER) JOIN без ON не является стандартным SQL. Запятая, CROSS JOIN & (ВНУТРЕННИЙ или любой НАРУЖНЫЙ) JOIN ON 0 = 0 возвращает декартово произведение.
Philipxy

-1

почему база данных не может понять, что если я присоединяюсь к этим таблицам, я хочу присоединить их к столбцам pk / fk?

Части причины:

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

2. Существуют различные типы объединений (слева, справа, внутри). Внутренние объединения - только 1 из них.

3 - Стандарт SQL может руководствоваться принципом языка более низкого уровня, который позволяет диалектам более высокого уровня формировать интеллект, используя его. Сравнение несколько понятнее, если вы думаете о языке 4-го поколения и о языке 3-го поколения. Фактически, один инструмент, который я использовал, IEF, позволил вам написать что-то вроде этого:

ReadEach Customer 
Where Customer Places Orders and That Customer LivesIn "California" 
and OrderValue > 100.00

Таким образом, ваше предложение интересно и может быть реализовано как часть стандарта или как хранимая процедура (по умолчанию используется Inner Join).


-10

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

Хорошо, учитывая это, мне в конечном итоге пришлось сдать этот экзамен; и чтобы передать это, я должен был отпустить . SQL - это больше крушение, чем кто-либо может допустить, его путь стандартизации - это полная катастрофа, а некоторые реализации угрожающе терпят крах . Тем не менее, это довольно удобно, в общем. (Я не K / V Luddite)

Внешние ключи, тогда ... совсем не удобно. Да, они являются важной концепцией в реляционной модели , но функция SQL с тем же именем не может сравниться.

Скажу прямо: не используйте эту функцию SQL, вызванную Foreign Keyвообще , пока вы не столкнетесь с какой-то большой системой с проблемами производительности. Явный сообщающий , какое поле является внешним ключом , и который не является только использоваться для индексации, и она невидима для пользователя БД.

Это вводит в заблуждение?
Да.

Собираются ли они сделать его более мощным сейчас, после 30 лет введения людей в заблуждение?
Нет шансов.

Полное игнорирование внешних ключей до тех пор, пока это необходимо ... исправил SQL для меня?
Да!

И какого чёрта всё это произошло в первую очередь?
Что ж, функция, которую мы называем внешними ключами, была добавлена ​​позже в SQL; SQL - это стандарт, развивающийся со временем снизу вверх. Продавцы реализовали смехотворные функции, в то время как стандартные кузова лицевые.

Внешние ключи, как было сказано, предназначены только для индексации, и нет доступной конструкции JOIN. (объединяется там, где делается с SELECTзапросами, JOINзапросы довольно недавние и предназначены только для SELECTфункциональности псевдонимов ) Вероятно, хотя вызов этого флага индексации FOREIGN KEYбыл хитрым взломом именования по сравнению с концепциями реляционной теории БД.


13
Что касается внешних ключей, я так понимаю, вы когда-нибудь касались только движка MyISAM в MySQL? Потому что, даже не обращая внимания на эту маленькую напыщенную речь, все в этом ответе неверно.

Fk не используются для индексации, на самом деле общая проблема заключается в том, чтобы не иметь индекса для столбца fk, что может оказать существенное влияние на производительность.
jmoreno
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.