Следует учитывать, что первичный ключ и кластерный индекс - это не одно и то же. Первичный ключ является ограничением и имеет дело с правилами, по которым живут данные (т. Е. Целостность данных); это не имеет ничего общего с эффективностью / производительностью. Первичный ключ требует, чтобы ключевые столбцы были уникальными (в комбинации) и НЕ ПУСТО (отдельно). PK применяется посредством уникального индекса, хотя он может быть кластеризованным или некластеризованным.
Кластерный индекс - это средство физического (т. Е. На диске) упорядочения данных в таблице и определения производительности; это не имеет ничего общего с целостностью данных. Кластерный индекс можеттребует, чтобы ключевые столбцы были уникальными (в комбинации), но это не обязательно. Однако, поскольку кластеризованный индекс является физическим порядком данных, он должен однозначно идентифицировать каждую строку независимо от того, что именно. Поэтому, если вы не установите для него уникальность, он создаст собственную уникальность через скрытый 4-байтовый столбец «уникальность». Этот столбец всегда присутствует в неуникальных кластеризованных индексах, но он не занимает места, когда ключевые поля уникальны (в комбинации). Чтобы собственными глазами увидеть, как работает этот столбец «уникальность» (как в кластеризованном индексе, так и в воздействии на некластеризованные индексы), пожалуйста, ознакомьтесь с этим тестовым сценарием, который я разместил на PasteBin: сценарий T-SQL, чтобы проверить размер Uniquifier .
Отсюда и главный вопрос:
Было бы более эффективно добавить id
поле автоинкремента и использовать его вместе с company_id
первичным ключом или добавить ненужные накладные расходы
объединяет эти два понятия, поэтому их необходимо рассматривать отдельно, хотя определенно есть некоторые совпадения.
Должен ли IDENTITY
быть добавлен столбец или это будет ненужными накладными расходами?
Если вы добавляете INT IDENTITY
столбец и используете его для создания PK, предполагая, что это будет Clustered PK, это добавляет 4 байта к каждой строке. Этот столбец видим и может использоваться в запросах. Его можно добавить в другие таблицы в качестве внешнего ключа, хотя в данном конкретном случае этого не произойдет.
Если вы не добавите INT IDENTITY
столбец, вы не сможете создать PK для этой таблицы. Тем не менее, вы все равно можете создать кластеризованный индекс в таблице, если вы не используете эту UNIQUE
опцию. В этом случае SQL Server добавит скрытый столбец с именем «uniquifier», который ведет себя так, как описано выше. Поскольку столбец скрыт, его нельзя использовать в запросах или в качестве ссылки для внешних ключей.
Таким образом, что касается эффективности, эти варианты примерно одинаковы. Да, при использовании неуникального кластеризованного индекса будет немного меньше места из-за того, что некоторые строки (с исходными значениями уникальных ключей) занимают 0 байтов, в то время как все строки в IDENTITY
/ PK будут занимать 4 байта. Но 0-байтовых строк будет недостаточно (особенно с ожидаемым небольшим количеством строк), чтобы когда-либо заметить разницу, не говоря уже о том, чтобы перевесить удобство использования ID
столбца в запросах.
Столбец INT IDENTITY или хэш org_path
сохраняемого вычисляемого столбца?
Учитывая, что вы не будете искать строки, основанные на org_path
значениях, нет смысла добавлять накладные расходы для сохраняемого вычисляемого столбца, а также необходимость вычислять этот хэш в запросах для сопоставления с вычисляемым столбцом (это был мой оригинальное предложение, доступное в истории изменений здесь , которое было основано на первоначальной формулировке / деталях Вопроса). В этом конкретном случае INT IDENTITY
столбец «ID», вероятно, является лучшим.
Порядок ключевых столбцов
Учитывая, что ID
столбец будет редко, если вообще когда-либо использоваться в запросах, и учитывая, что два основных сценария использования - это получение «всех строк» или «всех строк для данного company_id
», я бы создал PK на company_id, id
. А поскольку это означает, что строки не вставляются последовательно, я бы указал значение, FILLFACTOR
равное 90. Вам также нужно будет регулярно выполнять обслуживание индекса, чтобы уменьшить фрагментацию.
Второй вопрос
оказывает ли здесь влияние тот факт, что company_id является первичным ключом в другой таблице?
Нет.
Вызывать
Так как org_path
значения внутри company_id
являются уникальными, вы все равно должны создать Триггер, INSERT, UPDATE
чтобы применить это. В триггере выполните запрос IF EXISTS
с запросом, который, вероятно, выполняет операции a COUNT(*)
и GROUP BY company_id, org_path
. Если что-то найдено, выполните ROLLBACK
команду a для отмены операции DML, а затем RAISERROR
укажите, что есть дубликаты.
сличение
В моем первоначальном ответе ( на основе первоначальной редакции / разреженных детали вопроса, и доступны в истории изменений здесь ), я предложил , возможно , с помощью двоичного кода (т.е. _BIN2
) комплектовку. Теперь, когда мы имеем представление о том, что именно org_path
, я бы не рекомендовал использовать двоичную сортировку. Так будут диакритические знаки, вы действительно хотите использовать лингвистические эквивалентности.
Зачем тебе ПК?
Почему бы просто не использовать company_id как некластеризованный индекс?
Вы сказали, что чаще всего ищут все записи или by company_id
Редко обновляют
Редко удаляют
org_path, это единственная таблица, в которой он существует
Ответ от Мартина Смита может
дать вам то, что вам нужно. Я не знаком с тем, как автоматически добавлять 4-байтовое целочисленное уникальное значение.
Возможно, я что-то упускаю, но если у вас нет других проиндексированных столбцов, я не вижу в этом смысла в этом случае использования.
Если вас беспокоит DRI, таблицы должны использовать таблицу Company в качестве FK для company_id
источник
INCLUDE
столбец, но это еще хуже, поскольку он просто дублирует таблицу. Правда, ПК не нужен; Важной частью является кластерный индекс. Но как только у вас появится ИДЕНТИЧНОСТЬ, вы можете пойти с ПК. И, пожалуйста, смотрите новую ссылку в моем ответе для ознакомления с Uniquifier 😃