В рамках одного веб-приложения, над которым я работаю, все операции с базой данных абстрагируются с использованием некоторых общих репозиториев, определенных в Entity Framework ORM.
Однако, чтобы иметь простой дизайн для общих репозиториев, все задействованные таблицы должны определять уникальное целое число ( Int32
в C #, int
в SQL). До сих пор это всегда был ПК таблицы, а также IDENTITY
.
Внешние ключи интенсивно используются, и они ссылаются на эти целочисленные столбцы. Они необходимы как для согласованности, так и для генерации навигационных свойств ORM.
Прикладной уровень обычно выполняет следующие операции:
- начальная загрузка данных из таблицы (*) -
SELECT * FROM table
- Обновление -
UPDATE table SET Col1 = Val1 WHERE Id = IdVal
- Удалить -
DELETE FROM table WHERE Id = IdVal
- Вставить -
INSERT INTO table (cols) VALUES (...)
Менее частые операции:
- Массовая вставка - с
BULK INSERT ... into table
последующей (*) загрузкой всех данных (для получения сгенерированных идентификаторов) - Массовое удаление - это обычная операция удаления, но «громоздкая» с точки зрения ORM:
DELETE FROM table where OtherThanIdCol = SomeValue
- Массовое обновление - это обычная операция обновления, но «громоздкая» с точки зрения ORM:
UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue
* все небольшие таблицы кэшируются на уровне приложения и почти все SELECTs
не доходят до базы данных. Типичным шаблоном является начальная загрузка и множество INSERT
s, UPDATE
s и DELETE
s.
Исходя из текущего использования приложения, существует очень малая вероятность достижения 100M записей в любой из таблиц.
Вопрос: С точки зрения администратора баз данных, существуют ли серьезные проблемы, с которыми я могу столкнуться, имея такое ограничение дизайна таблицы?
[РЕДАКТИРОВАТЬ]
Прочитав ответы (спасибо за отличную обратную связь) и ссылки на статьи, я чувствую, что должен добавить больше деталей:
Текущая специфика приложения - я не упомянул о текущем веб-приложении, потому что хочу понять, можно ли повторно использовать модель и для других приложений. Тем не менее, мой частный случай - это приложение, которое извлекает много метаданных из DWH. Исходные данные довольно грязные (странным образом денормализованы, имеют некоторые несоответствия, во многих случаях нет естественного идентификатора и т. Д.), И мое приложение генерирует четко разделенные сущности. Также
IDENTITY
отображаются многие из сгенерированных идентификаторов ( ), чтобы пользователь мог использовать их в качестве бизнес-ключей. Это, помимо масштабного рефакторинга кода, исключает использование GUID .«они не должны быть единственным способом однозначно идентифицировать ряд» (Аарон Бертран ♦) - это очень хороший совет. Все мои таблицы также определяют УНИКАЛЬНОЕ ОГРАНИЧЕНИЕ, чтобы гарантировать, что бизнес-дубликаты не допускаются.
Дизайн, ориентированный на внешние приложения, и дизайн, основанный на базе данных - выбор дизайна обусловлен этими факторами
Ограничения Entity Framework - допускается использование нескольких столбцов PK, но их значения не могут быть обновлены
Пользовательские ограничения - наличие единого целочисленного ключа значительно упрощает структуры данных и код, отличный от SQL. Например: все списки значений имеют целочисленную клавишу и отображаемые значения. Что еще более важно, это гарантирует, что любая таблица, помеченная для кэширования, сможет быть помещена в
Unique int key -> value
карту.
Сложные запросы на выборку - это почти никогда не произойдет, потому что данные всех небольших таблиц (<20-30K записей) кэшируются на уровне приложения. Это немного усложняет жизнь при написании кода приложения (сложнее писать LINQ), но база данных гораздо лучше:
Представления списка - не будут генерировать
SELECT
запросы при загрузке (все кэшируется) или запросы, которые выглядят так:SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)
Все остальные необходимые значения выбираются с помощью поиска в кэше (O (1)), поэтому сложные запросы не будут создаваться.
Редактировать представления - сгенерирует
SELECT
утверждения вроде этого:SELECT allcolumns FROM BigTable WHERE PKId = value1
(все фильтры и значения int
s)
Ответы:
Помимо дополнительного дискового пространства (и, в свою очередь, использования памяти и ввода-вывода), нет никакого вреда в добавлении столбца IDENTITY даже в таблицы, в которых он не нужен (пример таблицы, в которой столбец IDENTITY не нужен). простая таблица соединений, например, сопоставление пользователя с его / ее разрешениями).
Я возражаю против слепого добавления их к каждой таблице в сообщении блога за 2010 год:
Но суррогатные ключи имеют действительные варианты использования - просто будьте осторожны, чтобы не предполагать, что они гарантируют уникальность (именно поэтому иногда их добавляют - они не должны быть единственным способом уникальной идентификации строки). Если вам необходимо использовать платформу ORM, а вашей платформе ORM требуются целочисленные ключи из одного столбца даже в тех случаях, когда ваш реальный ключ не является целым числом, или не единственным столбцом, или ни тем, ни другим, убедитесь, что вы задаете уникальные ограничения / индексы для ваших настоящих ключей тоже.
источник
Исходя из моего опыта, основной и непреодолимой причиной использования отдельного идентификатора для каждой таблицы является следующее:
Почти во всех случаях мой клиент давал клятву крови на этапе зачатия, что какое-то внешнее, «естественное» поле
XYZBLARGH_ID
навсегда останется уникальным и никогда не изменится для данной сущности, и никогда не будет использовано повторно, в конце концов появились случаи, когда Свойства первичного ключа были нарушены. Просто так не получается.Затем, с точки зрения администратора баз данных, вещи, которые делают БД медленной или раздутой, безусловно, не 4 байта (или что-то еще) в строке, а такие вещи, как неправильные или отсутствующие индексы, забытые реорганизации таблиц / индексов, неправильные параметры настройки ОЗУ / табличного пространства пренебрегая использованием переменных связывания и так далее. Они могут замедлить работу БД в 10, 100, 10000 раз, а не в дополнительном столбце идентификаторов.
Таким образом, даже если бы имелся технический, измеримый недостаток наличия дополнительных 32 битов на строку, вопрос не в том, можете ли вы оптимизировать идентификатор, а в том, будет ли идентификатор необходим в какой-то момент, что будет более скорее всего, чем нет. И я не собираюсь пренебрегать всеми «мягкими» выгодами от позиции разработки программного обеспечения (как, например, ваш пример ORM или тот факт, что это облегчает разработчикам программного обеспечения, когда все идентификаторы в проекте имеют одинаковый тип данных и т. Д.) ,
Примечание: обратите внимание, что вам не нужен отдельный идентификатор для
n:m
таблиц ассоциации, потому что для таких таблиц идентификаторы связанных объектов должны формировать первичный ключ. Контрпример - страннаяn:m
ассоциация, которая допускает множественные ассоциации между одними и теми же двумя сущностями по любой причудливой причине - тогда для создания PK им потребуется собственный столбец ID. Однако есть библиотеки ORM, которые не могут обрабатывать многоколоночные PK, поэтому это может быть причиной для снисхождения к разработчикам, если им приходится работать с такой библиотекой.источник
Если вы неизменно добавляете бессмысленный дополнительный столбец в каждую таблицу и ссылаетесь только на эти столбцы как на внешние ключи, то вы почти неизбежно сделаете базу данных более сложной и трудной в использовании. По сути, вы удалите данные, представляющие интерес для пользователей, из атрибутов внешнего ключа и заставите пользователя / приложение выполнить дополнительное объединение для получения той же информации. Запросы усложняются, работа оптимизатора усложняется и производительность может пострадать.
Ваши таблицы будут более редко заполнены «реальными» данными, чем они были бы в противном случае. Поэтому базу данных будет сложнее понять и проверить. Вы также можете столкнуться с трудностями или невозможностью применения определенных полезных ограничений (где ограничения могут включать несколько атрибутов, которых больше нет в одной таблице).
Я бы посоветовал вам более тщательно выбирать ключи и делать их целыми, только если / когда у вас есть для этого веские основания. Основывайте свои проекты баз данных на хорошем анализе, целостности данных, практичности и проверяемых результатах, а не полагаясь на догматические правила.
источник
По моему опыту работы с различными базами данных первичный ключ Integer всегда лучше, чем приложения, у которых вообще не определены ключи. Или у которых есть ключи, которые соединяют полдюжины столбцов varchar неуклюжими способами, которые не логичны ... (вздох)
Я видел приложения, которые переключались с целых ПК на GUID. Их причина была в том, что в некоторых случаях было необходимо объединить данные из нескольких исходных баз данных. Разработчики переключили все ключи на GUID, чтобы слияния могли происходить, не опасаясь коллизий данных, даже для таблиц, которые не были частью слияния (на тот случай, если эти таблицы когда-нибудь станут частью будущего слияния).
Я бы сказал, что целое число PK не будет кусать вас, если вы не планируете объединять данные из отдельных источников или у вас могут быть данные, выходящие за пределы ваших целочисленных пределов размера - это все весело и игры, пока у вас не хватит места для вставок ,
Я скажу, однако, что может иметь смысл установить кластеризованный индекс для столбца, отличного от вашего PK, если таблица будет запрашиваться чаще таким образом. Но это запутанный случай, особенно если основная масса обновлений и выборок основана на значениях PK.
источник
Положить в сторону:
Если вы используете массовое удаление / обновление там, где это необходимо, и имеете индексы для поддержки таких операций, я не думаю, что у вас возникнут проблемы из-за используемого вами стандарта PK.
Возможно, что если позже вы создадите запросы EF с объединениями и т. Д., То они не будут такими эффективными, как с хранилищем на основе естественного ключа, но я недостаточно знаю об этой области, чтобы сказать наверняка в любом случае.
источник
У вас есть несколько факторов, которые помогут вам,
Определение и спецификация
Если что-то определено как уникальное в задаче или законах физики, вы тратите время на суррогатный ключ.
Уникальность.
Для личной гигиены, объединений и высокоуровневых функций базы данных вам потребуется: (а) уникальный столбец, (б) уникальный ряд столбцов
Все достаточно нормализованные схемы (1NF) обеспечивают одно из следующего. Если они этого не делают, вы всегда должны создавать его. Если у вас есть список людей, желающих принять участие в воскресенье, и он включает фамилию и имя, вы захотите узнать, когда у вас есть два Джо Бобса.
Внедрение и оптимизация.
Int имеет тенденцию быть небольшой формой данных, быстрой для сравнения и равенства. Сравните это со строкой Unicode, чьи параметры сортировки могут зависеть от локали (местоположение и язык). Сохранение 4242 в строке ASCII / UTF8 занимает 4 байта. Сохраняя его как целое число, он умещается в 2 байта.
Поэтому, когда дело доходит до недостатков, у вас есть несколько факторов.
Путаница и двусмысленность.
Космос.
Целые числа по-прежнему добавляют место в строке. И, если вы не используете их, нет никакой цели.
Кластеризация.
Вы можете заказать данные только одним способом. Если вы вводите суррогатный ключ, который вам не нужен, вы кластеризуете этот путь или путь естественного ключа?
источник