Следует учитывать, что первичный ключ и кластерный индекс - это не одно и то же. Первичный ключ является ограничением и имеет дело с правилами, по которым живут данные (т. Е. Целостность данных); это не имеет ничего общего с эффективностью / производительностью. Первичный ключ требует, чтобы ключевые столбцы были уникальными (в комбинации) и НЕ ПУСТО (отдельно). 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, я бы не рекомендовал использовать двоичную сортировку. Так будут диакритические знаки, вы действительно хотите использовать лингвистические эквивалентности.