СПОЧАТКУ
Ви , ймовірно , не потрібні всі три колонки: 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 стовпці - поєднувати їх у значення первинного ключа, і це завжди унікальні цінності.
У такому підході вам просто потрібно:
Залиште таблиці як такі:
PkId INT IDENTITY(1,1) PRIMARY KEY
Це додає 0 байтів у кожен рядок, а не 8 або навіть 12.
- Визначте початковий діапазон для значень, створених додатком. Вони будуть більшими за поточне значення MAX у кожній таблиці, але менше, ніж стане мінімальним значенням для автоматично сформованих значень.
- Визначте, з якого значення повинен починатись автоматично створений діапазон. Між поточною величиною MAX та великою кількістю кімнати має бути достатньо місця , адже верхня межа - трохи більше 2,14 мільярда. Потім можна встановити це нове мінімальне значення насіння через DBCC CHECKIDENT .
- Оберніть код програми ВСТАВЛЕННЯ в
SET IDENTITY_INSERT {table_name} ON;і SET IDENTITY_INSERT {table_name} OFF;заяви.
ДРУГО, частина В
Різновидом на підході, зазначеним безпосередньо вище, було б, щоб у коді додатка вставлялися значення, починаючи з -1 і знижуючись звідти. Це залишає IDENTITYзначення як єдині, що піднімаються . Перевага тут полягає в тому, що ви не тільки не ускладнюєте схему, але і не потрібно турбуватися про набігання на ідентифікатори, що перекриваються (якщо значення, створені додатком, стикаються з новим автоматично створеним діапазоном). Це лише варіант, якщо ви вже не використовуєте негативні значення ідентифікатора (і людям здається досить рідкісним використання негативних значень на стовпцях, що автоматично створюються, тому це може бути можливим у більшості ситуацій).
У такому підході вам просто потрібно:
Залиште таблиці як такі:
PkId INT IDENTITY(1,1) PRIMARY KEY
Це додає 0 байтів у кожен рядок, а не 8 або навіть 12.
- Початковий діапазон для значень, створених додатком, буде
-1.
- Оберніть код програми ВСТАВЛЕННЯ в
SET IDENTITY_INSERT {table_name} ON;і SET IDENTITY_INSERT {table_name} OFF;заяви.
Тут вам все одно потрібно зробити 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.
- Початковий діапазон значень, створених додатком, буде набагато вище того, що, на вашу думку, наблизиться автоматично створених значень.
- Оберніть код програми ВСТАВЛЕННЯ в
SET IDENTITY_INSERT {table_name} ON;і SET IDENTITY_INSERT {table_name} OFF;заяви.
ВІДПОВІДЬ , через вимогу, що код з будь-якою SCOPE_IDENTITY()або @@IDENTITYвсе-таки функціонує належним чином, перехід на послідовності наразі не є варіантом, оскільки, здається, немає еквівалента цих функцій для послідовностей :-(. Сумно!