NHibernate и строковые первичные ключи - PullRequest
2 голосов
/ 26 февраля 2009

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

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

... почему это особенно плохо для NHibernate?

... и следите за этим ... если строки создают плохие первичные ключи, стоит ли заменять первичные ключи в базе данных на int или GUID или что-то подобное? (у нас всего около 25-30 столов)

Ответы [ 3 ]

5 голосов
/ 26 февраля 2009

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

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

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

Я не знаю точно, почему это действительно плохо в Hibernate (и NHibernate), но по моему опыту, потому что мое приложение имеет сложный граф объектов, которые часто имеют ссылки на другие постоянные объекты, часто в виде списков или наборов все ссылки хранятся с использованием идентификатора другого объекта, и из-за правил, которые я установил для каскадного сохранения, выборки и т. д., это будет означать, что первичные ключи используются ВСЕ время. Hibernate - что мне очень нравится - имеет тенденцию делать именно то, что ему говорят, и иногда люди (особенно я!) Говорят, что они делают действительно глупые вещи. В результате даже кажущиеся простыми обновления или запросы в конечном итоге генерируют довольно сложный SQL.

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

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

1 голос
/ 08 апреля 2009

Энди К, кажется, подразумевает, что строки не хранятся в байтах. Это было бы смешно! На самом деле все зависит от длины строки PK и используемой вами сортировки. Это может быть даже быстрее, чем bigint или int identity, и почти наверняка будет быстрее, чем Guids. Если вам все равно придется искать эти строки, тогда вам все равно потребуется индекс (возможно, даже кластерный индекс), так почему бы не сделать их PK!

0 голосов
/ 06 декабря 2010

Использование строк или символов добавляет огромное количество случайной сложности в вашу систему. Подумайте над этими вопросами:

  • как обращаться с чувствительностью к регистру;
  • как справиться с заполнением. NHibernate позволяет вставлять более короткую строку, и база данных автоматически добавит к ней отступы, но она не будет отражена в вашем постоянном объекте. Попытка извлечь объект снова с идентификатором в памяти возвращает ноль;
  • как решать проблемы с кодировкой. C # использует строки Unicode, ваша база данных не переносится. Можете ли вы рассказать, как будет осуществляться конвертация? Я так не думаю.
  • синтетические целочисленные ключи могут автоматически генерироваться большинством баз данных без особых усилий. С помощью струн вы, скорее всего, создадите их «вручную». Если вы не скроете их за фабрикой (в смысле DDD), полученный код будет загромождать модель вашего домена.

Хотя потери производительности, упомянутые andy K , могут уменьшиться из-за индексации, все же много раз вы выполняете сравнения идентификаторов в памяти (hash-maps?), И оптимизация БД там не применяется.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...