Повторная вставка строк с идентичными столбцами
Я реализую очередь в SQL Server (2008 R2), содержащую задания, которые должны быть выполнены. По завершении задание перемещается в таблицу истории, устанавливая флаг для успеха или неудачи. Элементы в таблице очередей имеют столбец идентификаторов в качестве первичного ключа. Очередь истории имеет комбо этого идентификатора и метку времени в виде PK.
Если задание не выполняется, я бы хотел, чтобы его можно было повторно запустить, и они думают так: переместить его обратно из таблицы истории и обратно в оперативную очередь. В целях отслеживания я хотел бы, чтобы у повторно вставленной строки был тот же идентификатор, что и у исходной записи, что вызывает проблемы, поскольку это столбец идентификаторов.
Я вижу два возможных решения:
1) Используйте IDENTITY_INSERT:
SET IDENTITY_INSERT TableName ON
-- Move from history to live queue
SET IDENTITY_INSERT TableName OFF
2) Создайте пользовательскую логику для генерации уникальных идентификаторов, например, получите максимальное значение идентификатора из очереди в реальном времени и из истории и добавьте один.
Я не вижу никаких реальных проблем с 2, кроме того, что он грязный, возможно, плохой работы и что он заставляет мою невротическую кожу ползать...
Вариант 1 мне нравится, но я недостаточно хорошо знаю последствия. Как это будет работать? И я знаю, что одновременное выполнение двух таблиц приведет к краху и сбою. Что произойдет, если два потока сделают это с одной и той же таблицей одновременно?
Является ли это вообще хорошим способом сделать это для обычно используемых хранимых процедур, или этот метод должен просто использоваться для пакетной вставки данных один раз в голубую луну?
Есть мысли о том, какой вариант лучше, или есть лучший способ?
4 ответа
Я бы пошел с вариантом 1 - использовать IDENTITY_INSERT
SET IDENTITY_INSERT TableName ON
-- Move from history to live queue
SET IDENTITY_INSERT TableName OFF
IDENTITY_INSERT
это параметр, который применяется к текущему соединению, поэтому, если другое соединение делает подобное, это не будет иметь никакого влияния. Единственное место, где вы получаете ошибку при ее использовании, это если вы пытаетесь установить ее ON
на другом столе, не поворачивая его OFF
на первом столе.
Разве вы не можете использовать исходное (живое) значение идентификатора для вставки в таблицу истории? Вы говорите, что комбинируете это с меткой времени в любом случае.
Я могу видеть потенциальную проблему производительности при повторном использовании значений идентификаторов, а именно, если столбец идентификаторов индексируется кластерным индексом.
Строгое растущее число приведет к тому, что вставленные строки будут всегда добавляться последними в кластеризованном индексе, и разделение страниц не произойдет.
Если вы начнете вставлять повторно используемые номера, то вы можете вызвать разделение страниц во время этих вставок. Если это проблема, зависит от вашего домена.
Предполагая, что в столбце "Идентификация очереди" указан столбец "Идентификаторы заданий", я думаю, что простейшим решением будет добавить новый столбец "OriginalJobID", который может иметь значение NULL, потенциально с FK, указывающим на таблицу истории. Затем, когда вы перезапускаете задание, дайте ему возможность получить новый идентификатор при добавлении в очередь, но сохраните ссылку на исходное задание в этом новом столбце.
Чтобы ответить "или эта техника должна использоваться только для пакетной вставки данных один раз в синюю луну", я бы сказал, да, определенно, это именно то, для чего оно.
К сожалению, @Damien_The_Unbeliever прав, я забыл, что IDENTITY_INSERT
настройка для каждого соединения. Было бы сложно получить реальную проблему с подходом вставки идентификаторов (было бы что-то вроде MARS, я думаю, или плохая обработка ошибок). Тем не менее, я думаю, что пытаться повторно использовать идентификаторы является ошибкой!