ПЕРВЫЙ
Вы , вероятно , не нужны все три колонки: old_id
, external_id
, new_id
. new_id
Колонна, будучи IDENTITY
, будет иметь новое значение , сгенерированное для каждой строки, даже при вставке в external_id
. Но, между old_id
и external_id
, они в значительной степени взаимоисключающие: либо old_id
значение уже есть, либо этот столбец, в текущей концепции, будет просто NULL
при использовании external_id
или new_id
. Поскольку вы не будете добавлять новый «внешний» идентификатор в строку, которая уже существует (то есть, в которой есть old_id
значение), и не будет никаких новых значений old_id
, то может быть один столбец, который используется для обеих целей.
Таким образом, избавьтесь от external_id
столбца и переименуйте, old_id
чтобы быть что-то вроде old_or_external_id
или как- то еще. Это не должно требовать каких-либо реальных изменений, но уменьшает некоторые осложнения. Самое большее, вам может понадобиться вызвать столбец external_id
, даже если он содержит «старые» значения, если код приложения уже написан для вставки external_id
.
Это уменьшает новую структуру, чтобы быть просто:
PkId AS AS COALESCE(old_or_external_id, new_id, -1) PERSISTED NOT NULL,
old_or_external_id INT NULL, -- values from existing record OR passed in from app
new_id INT IDENTITY(2000000, 1) NOT NULL
Теперь вы добавили только 8 байтов в строку вместо 12 байтов (при условии, что вы не используете SPARSE
опцию или сжатие данных). И вам не нужно было менять код, T-SQL или код приложения.
ВТОРОЙ
Продолжая этот путь упрощения, давайте посмотрим на то, что мы оставили:
old_or_external_id
Столбец либо имеет значение уже, или будет дан новое значение из приложения, или оставить как NULL
.
new_id
Всегда будет иметь новое значение , сгенерированное, но это значение будет использовано только если old_or_external_id
столбец NULL
.
Никогда не бывает времени, когда вам понадобятся значения как в, так old_or_external_id
и в new_id
. Да, будут времена, когда оба столбца имеют значения из-за new_id
того, что они являются IDENTITY
, но эти new_id
значения игнорируются. Опять же, эти два поля являются взаимоисключающими. И что теперь?
Теперь мы можем понять, зачем нам это было нужно external_id
. Учитывая , что можно вставить в IDENTITY
колонку с помощью SET IDENTITY_INSERT {table_name} ON;
, вы могли бы уйти с не делая никаких изменений схемы на всех, и только изменить код приложения , чтобы обернуть INSERT
заявления / операции в SET IDENTITY_INSERT {table_name} ON;
и SET IDENTITY_INSERT {table_name} OFF;
заявлении. Затем вам нужно определить, к какому начальному диапазону будет возвращаться IDENTITY
столбец (для вновь сгенерированных значений), так как он должен быть значительно выше значений, которые будет вставлять код приложения, поскольку при вставке более высокого значения следующее автоматически сгенерированное значение будет быть больше, чем текущее значение MAX. Но вы всегда можете вставить значение ниже значения IDENT_CURRENT .
Объединяя old_or_external_id
и new_id
столбцы также не увеличивают шансы нарваться значением ситуации , перекрывающей между автоматически сгенерированными значениями и приложениями сгенерированными значениями с целью имеющих 2 или даже 3, колонны, чтобы объединить их в значение первичного ключа, и это всегда уникальные ценности.
При таком подходе вам просто необходимо:
ВТОРАЯ, часть Б
Вариант подхода, отмеченного непосредственно выше, заключался бы в том, чтобы код приложения вставлял значения, начинающиеся с -1, и понижающиеся оттуда. Это оставляет IDENTITY
ценности как единственные, идущие вверх . Преимущество здесь в том, что вы не только не усложняете схему, но и не должны беспокоиться о том, чтобы столкнуться с перекрывающимися идентификаторами (если сгенерированные приложением значения попадают в новый автоматически сгенерированный диапазон). Это вариант, только если вы еще не используете отрицательные значения идентификаторов (и люди редко используют отрицательные значения в автоматически сгенерированных столбцах, поэтому в большинстве ситуаций это должно быть вероятно).
При таком подходе вам просто необходимо:
Здесь вам все еще нужно сделать IDENTITY_INSERT
, но: вы не добавляете новые столбцы, не нуждаетесь в том, чтобы «повторно заполнять» какие-либо IDENTITY
столбцы, и у вас нет будущего риска наложения.
ВТОРАЯ, часть 3
Последним вариантом этого подхода может быть замена IDENTITY
столбцов и использование последовательностей . Причиной такого подхода является наличие возможности вставлять в код приложения значения, которые являются: положительными, выше автоматически сгенерированного диапазона (не ниже) и не нуждаются в этом SET IDENTITY_INSERT ON / OFF
.
При таком подходе вам просто необходимо:
- Создать последовательности, используя CREATE SEQUENCE
Скопируйте IDENTITY
столбец в новый столбец, который не имеет IDENTITY
свойства, но имеет DEFAULT
ограничение, используя функцию NEXT VALUE FOR :
PkId INT PRIMARY KEY CONSTRAINT [DF_TableName_NextID] DEFAULT (NEXT VALUE FOR...)
Это добавляет 0 байтов к каждой строке вместо 8 или даже 12.
- Начальный диапазон для значений, сгенерированных приложением, будет намного выше того, что, как вы думаете, подойдет к автоматически сгенерированным значениям.
- Оберните код приложения INSERT в
SET IDENTITY_INSERT {table_name} ON;
и SET IDENTITY_INSERT {table_name} OFF;
заявления.
ОДНАКО , из-за требования, чтобы код с одним SCOPE_IDENTITY()
или @@IDENTITY
все еще функционировал должным образом, переключение на Последовательности в настоящее время не вариант, поскольку кажется, что нет эквивалента этих функций для Последовательностей :-(. Грустно!