Почему IDENTITY_INSERT ON допускается только для одной таблицы за раз?

20

Это тот случай, когда IDENTITY_INSERT может быть установлен только на ON в одной таблице базы данных одновременно, но почему? Поскольку IDENTITYстолбцы не являются глобально уникальными, я не могу вспомнить ни о какой опасной ситуации, которая могла бы быть вызвана вставкой идентификаторов в несколько таблиц одновременно (по крайней мере, не более опасно, чем в целом с использованием IDENTITY INSERT).

IDENTITY INSERT следует использовать редко, но в чем причина жесткого ограничения?

Бен Брока
источник
1
Сдерживающий может быть, поэтому он редко используется?
Ремус Русану
@RemusRusanu, это то, о чем я думал, либо чтобы, либо чтобы случайно не оставить II ON для нескольких таблиц.
Бен Брока
@Ben, почему случайно включить его для нескольких столов хуже, чем случайно оставить его для одного стола случайно? Оба могут привести к одной и той же проблеме. Мне искренне любопытен ваш вопрос, и я не думаю, что сдерживающий фактор - это ответ, иначе у нас было бы намного больше ограничений в двигателе. Но я согласен, что если вы чувствуете, что вам нужно делать это часто, возможно, есть что-то подозрительное.
Аарон Бертран
@AaronBertrand - это не так, как я и предполагал в вопросе Q. Также не уверен насчет сдерживающего фактора, поскольку SQL Server допускает множество других плохих практик, таких как присвоение имен столбцам с зарезервированными ключевыми словами (иногда даже если вы не используете []!)
Бен Брока
@ Правильно, это было не обязательно для вас, но для любого читателя, который сталкивался с вопросом.
Аарон Бертран

Ответы:

12

Я думаю, что это сделать это сложно. Если бы вы могли просто оставить его включенным все время, зачем вообще поле идентификации?

На самом деле есть пара ограничений:

  • Это сохраняется только на этой связи
  • Устанавливается только на одну таблицу для каждого соединения

Основываясь на ограничениях, связанных с подключением, я думаю, что это в основном так, что он никогда не остается случайно включенным.

Представьте, если кто-то включил вставку идентификатора в одну из ваших таблиц, то вы не поняли, и была выполнена (обычно) неверная вставка, которая нарушила целостность вашего поля идентификатора?

Имейте в виду, что поля идентификаторов могут иметь повторяющиеся значения, если нет ограничений или уникального индекса ...

JNK
источник
1
+1 Я думаю, что ваш последний пункт о дубликатах много пропущен. Люди думают, что если они IDENTITYэто установят, это тоже станет уникальным ограничением. Очень легко опровергнуть, конечно, если они хоть попробуют.
Аарон Бертран
@AaronBertrand Но опять-таки, риск дублирования идентификатора одинаков для любой таблицы с IDENTITY INSERT, почему жесткий лимит? Я думаю, что тот факт, что он сохраняется только для связи, имеет гораздо больше смысла в качестве меры предосторожности.
Бен Брока
Я не предполагал, что проблема с дублированием идентификатора была причиной жесткого ограничения.
Аарон Бертран
6

Я думаю, что это было ограничение из-за реализации. Разрешение этого параметра для нескольких таблиц было потенциальным ударом производительности:

Поскольку это параметр сеанса, разрешение активировать настройку для одной таблицы означает, что это простой флаг и идентификатор объекта таблицы для хранения в сеансе на стороне сервера. Может быть, это всего лишь одно целое число: 0, если IDENTITY_INSERT не активен, и некоторое кодирование databaseid + objectid для таблицы.

Разрешение установки параметра для нескольких таблиц в течение сеанса будет означать, что сервер будет хранить динамический список таких объектов и проверять его для каждого оператора вставки. Представьте себе, что сеанс активирует параметр для тысячи таблиц:

  1. Это означает, что сервер выделил 1000 элементов в переменной сеанса
  2. Это также означает, что сервер должен проверять список из 1000 элементов для каждого оператора вставки в этом сеансе.

Также я подозреваю, что set identity_insert имеет снижение производительности на сервере. В sybase существовал « коэффициент набора идентификаторов записи », который позволял сохранять значение счетчика идентификаторов таблицы, которая будет сохраняться только время от времени (значение сохраняется в памяти и время от времени записывается на диск и на сервер. неисправность ). SQL Server основан на том же коде, поэтому, вероятно, имеет некоторую сопоставимую оптимизацию, но активация identity_insert для таблицы, вероятно, заставляет сервер сохранять значение идентификатора для каждой вставки, поскольку в противном случае он не может гарантировать максимальный размер зазора. Поэтому, если один сеанс снижает производительность вставок в одной таблице, это, вероятно, приемлемо, но не в том случае, если он может повлиять на производительность всех таблиц auto_increment на сервере.

Оливье С
источник
+1 Наверное, немного правды здесь. Я не покупаю аргумент размера пропуска, поскольку INSERTза сеанс может работать только один , и я мог бы легко вставить 10 миллионов жестко закодированных IDENTITYзначений.
Аарон Бертран
Размер промежутка связан с тем, что происходит в случае сбоя: на sybase, если на сервере происходит сбой, последний идентификатор теряется (он находился в памяти), поэтому он перезапускается, оставляя разрыв (см. Фактор набора параметров записи)
Olivier S
Таким образом, в SQL Server вы предполагаете, что происходит что-то другое, если происходит сбой механизма при вставке 1 000 000 строк со столбцом идентификаторов или при переопределении столбца идентификаторов с 1 000 000 жестко закодированных значений, когда SET IDENTITY_INSERTвключено? Я просто предполагаю, что размер промежутка не влияет на несколько таблиц иначе, чем на одну таблицу.
Аарон Бертран
мое предположение - у меня нет абсолютно никаких доказательств этого - заключается в том, что SET IDENTITY_INSERT для таблицы принудительно записывает на диск автоинкремент при каждой вставке. Обоснованием может быть то, что, поскольку значение, которое вы вставляете, может быть любым, сервер не может считать «хорошо, если я записываю на диск только один раз каждые 1000 строк, в случае сбоя я могу смело добавить 1000 к последнему сохраненному значению»
Оливье С