NEWID() для INT (BigInt, SmallInt) в T-SQL
По ходу работы столкнулся со следующей проблемой — необходимо было сгенерировать уникальный в пределах БД показатель типа INT. Вообще, для uniqueidentifier существет такая замечательная функция NEWID(), которая генерирует заветное значение, а вот для INT'а подобную функцию придется реализовывать самостоятельно.
Вообще, сделать подобно можно, сохранив уже сгенерированные IDшники в какую-нибудь таблицу. Но как реализовать генерацию нового значения?
Первой мыслью было использование транзакций, нахождение максимального числа с последующим его увеличением. Конечно, такой вариант тоже «прокатывает», но параноик-кун, затаившийся внутри меня, кричал о возможных таймаутах, ошибках в транзакции и прочих невкусностях.
И тут мне пришла довольно интересная идея, которую вкратце можно описать следующим алгоритмом:
1) создаем служебнную таблицу с 2мя полями — ID_int (типа int) и ID_guid (типа uniqueidentifier);
2) ставим автоинкремент и PK на ID_int;
3) создаем процедуру, которая вставляет в таблицу значение с новым гуидом;
4) выбираем по созданному гуиду интовский IDшник;
[5)] при необходимости удаляем строку (если место критическое).
Сказано — сделано: реализация.
1, 2) создание таблицы с автоинкрементом
2, 3, 4) создание процедуры
Плюсы и минусы подхода
плюс Никаких транзакций, реализуемых вручную.
плюс-минус В данном подходе используется процедура, а не функция, что доставляет некоторые неудобства (возможно, кому-то понравится).
минус Уязвимость к удалению служебной таблицы, но этот минус можно отнести к подходу в целом.
Готов дополнить статью вашими и своими идеями (в данный момент как раз занимаюсь этой проблемой).
Что дальше — варианты развития идеи
Данный код уже можно использовать, но возможно и его улучшение — например, если посмотреть Tuning Advisor'ом (я работаю с MS SQL Server) на текст хранимки, то можно получить рекомендации по расставлению индексов в данную таблицу (это при условии изменения ХП, если оставить «как есть», то индексы не нужны). Еще одним направлением по универсализации кода может быть проверка на наличие таблицы, которую мы создавали вручную, и её создание при необходимости. Ну и, конечно же, стоит присмотреться к отлову исключений.
П.С. Можно возвращать значения из ХП иначе, просто мне удобнее делать это через OUTPUT.
П.П.С. Для BigInt и SmallInt делать можно по аналогии с Int.
Вообще, сделать подобно можно, сохранив уже сгенерированные IDшники в какую-нибудь таблицу. Но как реализовать генерацию нового значения?
Первой мыслью было использование транзакций, нахождение максимального числа с последующим его увеличением. Конечно, такой вариант тоже «прокатывает», но параноик-кун, затаившийся внутри меня, кричал о возможных таймаутах, ошибках в транзакции и прочих невкусностях.
И тут мне пришла довольно интересная идея, которую вкратце можно описать следующим алгоритмом:
1) создаем служебнную таблицу с 2мя полями — ID_int (типа int) и ID_guid (типа uniqueidentifier);
2) ставим автоинкремент и PK на ID_int;
3) создаем процедуру, которая вставляет в таблицу значение с новым гуидом;
4) выбираем по созданному гуиду интовский IDшник;
[5)] при необходимости удаляем строку (если место критическое).
Сказано — сделано: реализация.
1, 2) создание таблицы с автоинкрементом
USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[sys_NEWID_INT](
[ID_INT] [int] IDENTITY(1,1) NOT NULL,
[ID_GUID] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_sys_NEWID_INT] PRIMARY KEY CLUSTERED
(
[ID_INT] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
2, 3, 4) создание процедуры
USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[syssp_NEWID_INT](@ID_int int OUTPUT)
AS
BEGIN
DECLARE @ID_G uniqueidentifier
SET @ID_G = NEWID()
SET @ID_int = NULL
INSERT
INTO [sys_NEWID_INT]([ID_GUID])
VALUES (@ID_G)
SELECT @ID_int = ID_INT
FROM [sys_NEWID_INT]
WHERE ID_GUID = @ID_G
DELETE
FROM [sys_NEWID_INT]
WHERE ID_INT = @ID_int
END
Плюсы и минусы подхода
плюс Никаких транзакций, реализуемых вручную.
плюс-минус В данном подходе используется процедура, а не функция, что доставляет некоторые неудобства (возможно, кому-то понравится).
минус Уязвимость к удалению служебной таблицы, но этот минус можно отнести к подходу в целом.
Готов дополнить статью вашими и своими идеями (в данный момент как раз занимаюсь этой проблемой).
Что дальше — варианты развития идеи
Данный код уже можно использовать, но возможно и его улучшение — например, если посмотреть Tuning Advisor'ом (я работаю с MS SQL Server) на текст хранимки, то можно получить рекомендации по расставлению индексов в данную таблицу (это при условии изменения ХП, если оставить «как есть», то индексы не нужны). Еще одним направлением по универсализации кода может быть проверка на наличие таблицы, которую мы создавали вручную, и её создание при необходимости. Ну и, конечно же, стоит присмотреться к отлову исключений.
П.С. Можно возвращать значения из ХП иначе, просто мне удобнее делать это через OUTPUT.
П.П.С. Для BigInt и SmallInt делать можно по аналогии с Int.
0 комментариев