MySQL - я должен использовать первичные ключи с несколькими столбцами на каждой дочерней таблице? - PullRequest
0 голосов
/ 09 сентября 2011

Установка:

Я пытался понять разницу между идентифицирующими и неидентифицирующими отношениями, когда нашел эту замечательную статью о stackexchange. В чем разница между идентифицирующими и неидентифицирующими отношениями?

Прочитав несколько комментариев, я вспомнил еще один вопрос о проблеме, с которой я столкнулся.


Вопрос:

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

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


Пример:

В моей ситуации я знаю building_id, и мне нужно получить bed.data.

# 1 - Моя текущая структура БД:

TABLE { FIELDS }
-----------------------------------------------------------------------
building { id, data } 
floor { id, building_id, data }
room {id, floor_id, data }
bed {id, room_id, data }

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

# 2 - Моя интерпретация предложенной БД Карвином структуры БД (см. Комментарии к статье ниже):

TABLE { FIELDS }
-----------------------------------------------------------------------
building { id, data } 
floor { id, building_id, data }
room {id, building_id, floor_id, data }
bed {id, building_id, floor_id, room_id, data }

Эта структура таблицы, кажется, устраняет необходимость объединений в моей ситуации. Итак, каковы недостатки этой структуры таблицы? Мне очень нравится идея не делать так много операторов объединения.


Комментарии от статьи:

В чем разница между идентифицирующими и неидентифицирующими отношениями?

@ hobodave: Это аргумент "соглашение о конфигурации". Некоторые школы считают, что каждая таблица должна определять свой первичный ключ для псевдоключа с одним столбцом с именем id, который автоматически генерирует ее значения. Фреймворки приложений, такие как Rails, сделали это популярным по умолчанию. Они рассматривают естественные ключи и ключи из нескольких столбцов как отличающиеся от их соглашений, необходимых при использовании «старых» баз данных. Многие другие рамки последовали этому примеру. - Билл Карвин 10 марта 2010 года в 23: 06

Похоже, что "правильное" построение идентифицирующих отношений приведет к неприятно огромным первичным ключам. например Здание имеет Этаж имеет Комната имеет Кровать. PK для кровати будет (bed_id, floor_id, room_id, building_id). Кажется странным, что я никогда не видел это на практике и не слышал, чтобы это предлагалось как способ что-либо сделать. Это много избыточных данных в ПК. - hobodave 10 марта 2010 года в 23: 34

@ hobodave: я видел многоколонные первичные ключи, которые еще больше. Но я понимаю вашу точку зрения. Учтите, что многоколонные первичные ключи передают больше информации; Вы можете запросить таблицу кроватей для всех кроватей в конкретном здании без каких-либо соединений. - Билл Карвин 11 марта 2010 года в 1: 00

Ответы [ 3 ]

3 голосов
/ 09 сентября 2011

Я думаю, маловероятно, что ваш # 2 - это то, что имел в виду Билл Карвин. Обычно «id» подразумевает автоматическую числовую последовательность. Я думаю, что более вероятно, что он имел в виду что-то подобное. Столбцы, составляющие первичные ключи, находятся между звездочками.

TABLE    { COLUMNS }
-----------------------------------------------------------------------
building { *building_id*, other columns } 
floor    { *building_id, floor_num*, other columns }
room     { *building_id, floor_num, room_num*, other columns }
bed      { *building_id, floor_num, room_num, bed_num* (?), other columns }

Я не уверен, какие еще колонки у вас могут быть для "кровати", хотя. Близнец, Полный, Королева, Король? Это может иметь смысл. Если это так, то эта таблица

bed      { *building_id, floor_num, room_num, bed_num*, bed_size }

далеко не "денормализован". На самом деле это в 5NF.

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

3 голосов
/ 09 сентября 2011

эти данные нормализованы

TABLE { FIELDS }
-----------------------------------------------------------------------
building { id, data } 
floor { id, building_id, data }
room {id, floor_id, data }
bed {id, room_id, data }

Эта таблица не является (плохая идея)

TABLE { FIELDS }
-----------------------------------------------------------------------
building { id, data } 
floor { id, building_id, data }
room {id, building_id, floor_id, data }
bed {id, building_id, floor_id, room_id, data }
  1. В первой (хорошей) таблице у вас нет ненужных дублированных данных.
  2. Вставки в первую таблицу будут намного быстрее.
  3. Первые таблицы будут легче помещаться в памяти, ускоряя ваши запросы.
  4. InnoDB оптимизирован для модели A, а не для модели B.
  5. В последней (плохой) таблице есть дублированные данные, , если не синхронизирован, у вас будет беспорядок. DB A не может быть намного труднее выйти из синхронизации, потому что данные перечислены только один раз.
  6. Если я хочу объединить данные от здания, пола, комнаты и кровати, мне нужно будет объединить все четыре стола в модели A, а также в модели B, как вы экономите время здесь.
  7. InnoDB хранит индексированные данные в своем собственном файле, , если вы select только индексируете , сами таблицы никогда не будут доступны 1028 *. Так почему вы дублируете индексы? В любом случае MySQL никогда не нужно будет читать основную таблицу.
  8. InnoDB сохраняет PK в каждом вторичном индексе , с составным и, следовательно, длинным PK, вы замедляете каждый выбор, использующий индекс, и увеличиваете размер файла; без выгоды, что так всегда.
  9. У вас есть серьезные проблемы со скоростью? Если нет, то вы денормализуете свои таблицы?
  10. Даже не думайте об использовании MyISAM, который меньше страдает от этих проблем, он не оптимизирован для баз данных с несколькими соединениями и не поддерживает ссылочную нестабильность или транзакции и плохо подходит для этой рабочей нагрузки.
  11. При использовании составного ключа вы можете использовать только самую правую часть ключа, т.е. вы не можете использовать floor_id в таблице bed, кроме id+building_id+floor_id. Это означает, что вам, возможно, придется использовать гораздо больше пространство клавиш, чем необходимо в модели A. Либо это, либо вам нужно добавить дополнительный индекс (который будет перетаскивать полную копию PK).

Короче
Я вижу абсолютно нулевую выгоду и массу недостатков в модели B, никогда не используйте ее!

0 голосов
/ 09 сентября 2011

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

  1. Если вы используете innodb, этот ключ будет добавлен ко всем вторичным ключам в этой таблице.
  2. Если вы используете интерфейс для управления слоями, будет удобно использовать один идентификатор поля для работы с конкретными строками, а не с тремя полями.
  3. Если вы хотите гарантировать уникальность строки, вы можете использовать UNIQUE KEY в этих 3 полях.
...