#foreign-keys
#внешние ключи
Вопрос:
У меня есть следующие две таблицы mysql для основного дискуссионного форума. Первая таблица содержит разделы, в то время как вторая содержит ответы на конкретную тему. Я хочу знать о концепции внешнего ключа в этом дизайне базы данных. Нужно ли мне добавлять сюда внешний ключ? Чем это будет полезно и как я могу добавить в следующие таблицы. Спасибо.
--
-- Table structure for table `topics`
--
CREATE TABLE IF NOT EXISTS `topics` (
`topic_id` int(11) NOT NULL AUTO_INCREMENT,
`topic_title` varchar(255) NOT NULL,
`topic_content` text NOT NULL,
`topic_author_id` int(11) NOT NULL,
`topic_date` int(10) NOT NULL,
PRIMARY KEY (`topic_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
--
-- Table structure for table `replies`
--
CREATE TABLE IF NOT EXISTS `replies` (
`reply_id` int(11) NOT NULL AUTO_INCREMENT,
`reply_topic_id` int(11) NOT NULL,
`reply_content` text NOT NULL,
`reply_author_id` int(11) NOT NULL,
`reply_date` int(10) NOT NULL,
PRIMARY KEY (`reply_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Ответ №1:
Технически внешний ключ не требуется, но с точки зрения качества данных он настоятельно рекомендуется.
Внешний ключ устанавливает связь между двумя таблицами — он определяет и гарантирует, что :
-
у вас нет дочерних строк (в
replies
), которые ссылаются на родительскую строку (вtopics
), которая не существует («данные зомби») -
это гарантирует, что вы случайно не удалите родительскую строку, пока вокруг все еще есть дочерние строки
и в целом, это обеспечивает качество и целостность ваших данных — настоятельно рекомендуемое свойство в вашей базе данных!
Ответ №2:
В общем случае MySQL не требует, чтобы вы вставляли внешние ключи. Более того, пока вы используете механизм хранения MyISAM, вы не сможете извлечь выгоду из определения внешних ключей. Они принимают синтаксис внешнего ключа, но внутренне они просто игнорируют эти инструкции, см. Запись внешнего ключа в документации MySQL для деталей.
Вместо этого вы могли бы рассмотреть возможность определения дополнительных индексов для столбцов внешнего ключа, что может повысить производительность вашего запроса. Вы можете определить индекс вместе с определением вашей таблицы
CREATE TABLE IF NOT EXISTS `replies` (
`reply_id` int(11) NOT NULL AUTO_INCREMENT,
`reply_topic_id` int(11) NOT NULL,
`reply_content` text NOT NULL,
`reply_author_id` int(11) NOT NULL,
`reply_date` int(10) NOT NULL,
PRIMARY KEY (`reply_id`),
INDEX (`reply_topic_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Подробности см. в синтаксисе mysql create table.
В качестве альтернативы вы могли бы рассмотреть возможность замены вашего механизма хранения на InnoDB и использовать внешние ключи, которые автоматически добавят индексы к необходимым столбцам. Но вы выиграете, только если вам действительно понадобятся другие функции помимо оптимизации производительности, такие как ограничения внешнего ключа.
Как правило, можно придерживаться предложений, приведенных в руководстве mysql. Если вам не нужны дополнительные преимущества, такие как ограничения, механизм хранения MyISAM обеспечит лучшую производительность. Итак, если вы не хотите, чтобы база данных обеспечивала ссылочную целостность, вместо этого делая это самостоятельно в своем приложении, то MyISAM с надлежащими индексами будет более быстрым и высокопроизводительным решением. Если вы хотите, чтобы ваша база данных обеспечивала ссылочную целостность, затем переключитесь на механизм хранения InnoDB и определите внешние ключи с надлежащими ограничениями.
Комментарии:
1. Спасибо за ваш ответ. Не могли бы вы привести пример, как я могу добавить индексы к обеим таблицам выше?
2. еще раз спасибо за ваш ответ. Можете ли вы сказать мне, какой метод лучше, добавление индекса или использование внешних ключей путем изменения механизма хранения на InnoDB. Я просто обеспокоен производительностью и т.д.
3. @Roman: Включил несколько советов о том, когда переключаться на InnoDB. Надеюсь, это поможет с вашим решением.
Ответ №3:
В replies
таблице должен быть столбец, содержащий topic_id
тему в topics
таблице, для которой предназначен конкретный ответ в replies
таблице.
например
`topic_id` int(11) FOREIGN KEY REFERENCES `topics`(`topic_id`)
Комментарии:
1. но у меня уже есть столбец в таблице ответов
reply_topic_id
, это имя в порядке, или оно должно быть точнымtopic_id
? В чем преимущество добавления внешнего ключа в таблицу?2. Я пропустил
reply_topic_id
вreplies
таблице. Мне следовало более внимательно прочитать вопрос. Нет, имя этого столбца не обязательно должно совпадать с именем столбца, на который он ссылается. Итак, вам просто нужно добавить:reply_topic_id
int(11) ССЫЛКИ НА ВНЕШНИЕ КЛЮЧИtopics
(topic_id
) Добавление внешнего ключа позволяет проверять ссылочную целостность. Всякий раз, когда вы вставляете новую строку вreplies
таблицу, СУБД гарантирует, чтоreply_topic_id
столбец новой строки содержит значение, которое присутствует вtopic_id
столбцеtopics
таблицы. Если нет, это уведомит вас об ошибке.