Почему составные ключи не поощряются в hibernate?

Это Hibernate официальный учебник:

есть альтернатива <composite-id> объявление, которое позволяет получить доступ к устаревшим данным с составными ключами. Ее использование не рекомендуется для чего другого.

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

какова альтернатива? Создать дополнительный автоматически сгенерированный столбец и использовать его в качестве первичного ключа? Мне все равно нужно запросить мои 3 столбца!?

короче, Почему это утверждение истинно? а какая альтернатива лучше?

5 ответов


они отбивают их по нескольким причинам:

  • они громоздкие в использовании. Каждый раз, когда вам нужно ссылаться на объект (или строку), для eexample в вашем веб-приложении вам нужно передать 3 параметра вместо одного.
  • они неэффективны. Вместо простого хэширования целого числа база данных должна хэшировать композит из 3 столбцов.
  • они приводят к ошибкам: разработчики неизбежно реализуют методы equals и hashCode класса primary key неправильно. Или они делают его изменяемым и изменяют свое значение, хранящееся в HashSet или HashMap
  • они загрязняют схемы. Если другая таблица должна ссылаться на эту таблицу с 3 столбцами, ей нужно будет иметь 3 столбца вместо одного в качестве внешнего ключа. Теперь предположим, что вы следуете той же схеме и делаете этот 3-столбчатый внешний ключ частью первичного ключа этой новой таблицы, у вас быстро будет 4-столбчатый первичный ключ, а затем 5-столбчатый ПК в следующей таблице и т. д. так далее., ведущий к дублирование данных и грязная схема.

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


даже если это-может быть-слишком поздно, чтобы ответить на ваш вопрос, я хочу здесь дать другую точку зрения (более умеренную, я надеюсь) на необходимость (это действительно совет ?) из Hibernate использовать суррогатные ключи.

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

мифы о природных ключах

  1. составные ключи менее эффективны, чем суррогатные ключи. Нет! Это зависит от используемой СУБД :
  2. естественные ключи не существуют в реальный. Извините, но они существуют! В авиационной промышленности, например, следующий кортеж всегда будет уникальным в отношении данного назначена полет (авиакомпания, departureDate, flightNumber, operationalSuffix). В более общем случае, когда набор данных является гарантированно уникальным данным стандартный тогда этот набор данных является [хорошим] естественным ключевым кандидатом.
  3. естественные ключи "загрязняют схему" дочерних таблиц. Для меня это больше чувство, чем реальность. проблема. Наличие первичного ключа из 4 столбцов по 2 байта каждый может быть более эффективным, чем один столбец из 11 байтов. Кроме того, 4 столбца можно использовать для прямого запроса дочерней таблицы (используя 4 столбца в предложении where) без присоединения к родительской таблице.

недостатки суррогатных ключей

суррогатными ключами являются:

  1. источник проблем с производительностью:
    • они обычно реализуются с помощью автоматического увеличения столбцы, которые означают:
      • туда и обратно в базу данных каждый раз, когда вы хотите получить новый идентификатор (я знаю, что это можно улучшить с помощью алгоритмов кэширования или [seq]hilo, но все же эти методы имеют свои недостатки).
      • если однажды вам нужно переместить данные из одной схемы в другую (это происходит довольно регулярно в моей компании, по крайней мере), то вы можете столкнуться с проблемами столкновения Id. И да, я знаю, что вы можете использовать UUID, но для этого требуется 32 шестнадцатеричных цифры! (Если вы заботитесь о размере базы данных, это может быть проблемой).
      • если вы используете одну последовательность для всех ваших суррогатных ключей, то-наверняка-вы закончите с конфликтом в своей базе данных.
  2. ошибок. Последовательность имеет предел массив, так как разработчик - вы должны направить внимание на следующие факты:
    • вы должны задействовать свою последовательность ( при достижении максимального значения она возвращается к 1,2,...).
    • если вы используете последовательность в качестве заказа (с течением времени) ваших данных, то вы должны обрабатывать случай циклирования (столбец с идентификатором 1 может быть новее, чем строка с идентификатором max-value - 1).
    • убедитесь, что ваш код (и даже ваши клиентские интерфейсы, которые не должны происходить, как это должно быть внутренним идентификатором) поддерживает 32B/64b целых чисел, которые вы использовали для хранения значений последовательности.
  3. они не гарантируют не дублированные данные. Вы всегда есть 2 строки с одинаковыми значениями столбцов, но с другой сгенерированное значение. Для меня это на проблема суррогатных Ключей с точки зрения дизайна базы данных.
  4. подробнее в Википедии...

почему Hibernate предпочитает / нуждается в суррогатных ключах ?

Как говорится в персистентности Java с Hibernate ссылки:

более опытные пользователи Hibernate используют saveOrUpdate() исключительно; это гораздо проще позволить Hibernate решать, что новое, а что старое, особенно в более сложной сети объектов со смешанным состоянием. Этот единственным (не очень серьезным) недостатком exclusive saveOrUpdate () является что иногда он не может угадать, является ли экземпляр старым или новым без запуска SELECT в базе данных-например, когда класс сопоставляется с естественной составной ключ и версия или timestamp свойство.

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

вывод

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

надеюсь, что это помогло кому-то!


Я бы рассмотрел проблему с точки зрения дизайна. Это не просто, если Hibernate считает их хорошими или плохими. Настоящий вопрос:являются ли естественные ключи хорошими кандидатами, чтобы быть хорошими идентификаторами для моих данных?

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

наличие суррогатного ПК удобно, потому что он не цепляется как ваши данные в хранилище С структура бизнес-модели.

естественные ключи не могут быть сгенерированы из последовательности, а случай данных, которые не могут быть идентифицированы его данными, -много более частыми. Это доказательство того, что natural keys отличаются от ключа хранения, и их нельзя рассматривать как общий (и хороший) подход.

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

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

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


если документация Hibernate правильно понята:

"есть альтернатива <composite-id> объявление, которое позволяет получить доступ к устаревшим данным с составными ключами. Ее использование не рекомендуется для чего другого."

по теме 5.1.4. id tag xml <id> что позволяет сопоставление первичного ключа, сделанное слишком рано, мы можем заключить, что документация hibernate препятствует использованию <composite-id> вместо <id> XML-тег для сопоставления составного первичного ключа и не никаких ссылок отрицательным использовать составные первичные ключи.


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

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

So вместо одного метода будучи предпочтительным для другого, возможно, одна директива выгодна для другого, для ключевого построения: вы не будете разрабатывать приложение Hibernate очень легко использовать прямой доступ к экземпляру системы SSAS.

Я развиваюсь, используя обе ключевые смеси, и чувствую, что для реализации шаблона solid star или snowflake суррогат с кластеризованным индексом обычно является моим первым выбором.

Итак, с уважением OP и других, глядя: если вы хотите остаться DB инвариантным с вашим разработка (на которой специализируется Hibernate) -- используйте суррогатный метод, и когда чтение данных замедляется или вы замечаете, что определенные запросы истощают производительность, вернитесь к вашей конкретной базе данных и добавьте составные кластеризованные индексы, которые оптимизируют порядок запросов.