Sequence

by Alexey Knyazev 19. августа 2011 17:18

В SQL:2003 появилась возможность определения нового вида объектов базы данных – генераторов последовательностей (sequence generators). Такого рода объекты производят изменяемые во времени точные числовые значения. Генераторы последовательностей могут оказаться полезными в разных контекстах среды SQL. При этом они уже давно присутствуют в большинстве реляционных базах данных таких, как Oracle, DB2, PostgreSQL и т.д.

В новой версии SQL Server под кодовым названием Denali (SQL Server 2011) так же появились Sequence (последовательности). Последовательность представляет собой определяемый пользователем объект, привязанный к схеме, который формирует последовательность числовых значений в соответствии со спецификацией, с которой эта последовательность создавалась. Последовательность числовых значений формируется в возрастающем или убывающем порядке с заданным интервалом; можно настроить перезапуск (зацикливание) последовательности, когда она исчерпана. В отличие от столбцов идентификаторов последовательности не связаны с конкретными таблицами. Приложение обращается к объекту последовательности, чтобы получить следующее значение. Приложения управляют связями между последовательностями и таблицами. Пользовательские приложения могут ссылаться на объект последовательности и распределять значения между несколькими строками и таблицами.

Синтаксис команды:
CREATE SEQUENCE [schema_name . ] sequence_name
    [ AS [ built_in_integer_type | user-defined_integer_type ] ]
    [ START WITH  ]
    [ INCREMENT BY  ]
    [ { MINVALUE [  ] } | { NO MINVALUE } ]
    [ { MAXVALUE [  ] } | { NO MAXVALUE } ]
    [ CYCLE | { NO CYCLE } ]
    [ { CACHE [  ] } | { NO CACHE } ]
    [ ; ]
Параметры:

sequence_name
Указывает уникальное имя, под которым последовательность известна в базе данных. Тип sysname.

[ built_in_integer_type | user-defined_integer_type
Последовательность может быть определена с любым целочисленным типом. Допускаются следующие типы.

  • tinyint — диапазон от 0 до 255

  • smallint — диапазон от -32 768 до 32 767

  • int — диапазон от -2 147 483 648 до 2 147 483 647

  • bigint — диапазон от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807

  • decimal и numeric с масштабом 0.

  • Любой определяемый пользователем тип данных (псевдоним типа), основанный на одном из допустимых типов.

Если тип данных не указан, то по умолчанию используется тип bigint.

START WITH
Первое значение, возвращаемое объектом последовательности. Значение START должно быть не больше максимального и не меньше минимального значения объекта последовательности. По умолчанию начальным значением для нового объекта последовательности служит минимальное значение для объекта возрастающей последовательности и максимальное — для объекта убывающей.

INCREMENT BY <константа>
Значение, на которое увеличивается (или уменьшается, если оно отрицательное) значение объекта последовательности при каждом вызове функции NEXT VALUE FOR. Если значение приращения отрицательно, то объект последовательности убывает, в противном случае — возрастает. Приращение не может быть равно 0. По умолчанию для нового объекта последовательности используется приращение 1.

[ MINVALUE | NO MINVALUE ]
Указывает граничные значения для объекта последовательности. По умолчанию минимальным значением для нового объекта последовательности служит минимальное значение для типа данных объекта последовательности. Для типа данных tinyint это ноль, для всех остальных типов данных — отрицательное число.

[ MAXVALUE | NO MAXVALUE
Указывает граничные значения для объекта последовательности. По умолчанию максимальным значением для нового объекта последовательности служит максимальное значение для типа данных объекта последовательности.

[ CYCLE | NO CYCLE ]
Свойство, которое указывает, перезапускается объект последовательности с минимального значения (или максимального для объектов убывающих последовательностей) или вызывает исключение, когда достигнуто максимальное (или максимальное) значение. По умолчанию для новых объектов последовательности используется параметр цикличности NO CYCLE.
Учтите, что циклическое повторение начинается не с начального, а с минимального или максимального значения.

[ CACHE [ ] | NO CACHE ]
Повышает производительность для приложений, использующих объекты последовательностей, сводя к минимуму число операций дискового ввода-вывода, которые требуются для создания порядковых номеров.
Например, если выбран размер кэша 50, то SQL Server не кэширует 50 отдельных значений. Кэшируется только текущее значение и число значений, оставшихся в кэше. Это значит, что объем памяти для хранения кэша всегда равен размеру двух экземпляров типа данных объекта последовательности.
Если создание проводилось с параметром CACHE, то непредвиденное завершение работы (например, сбой электропитания) может привести к потере порядковых номеров, оставшихся в кэше.

Последовательность можно создать не только с помощью скрипта на T-SQL, но и через SQL Server Management Studio (SSMS):



При двойном клике по Sequence или при выборе пункта меню "New Sequence...", открывается окно в котором мы так же можем задать все параметры для последовательности:



Теперь попробуем пройтись по всем параметрам (аргументам) sequence более подробно.
Минимальная и достаточная инструкция для создания последовательности:
create sequence dbo.seq01
Информацию о всех последовательностях БД можно просматривать с помощью системного представления sys.sequences
Первые 12 полей этого представления полностью дублируют поля другого системного представления sys.objects. Тут же отмечу, что новый объект БД sequence имеет краткое обозначение - SO (SEQUENCE_OBJECT). Ниже проиллюстрирована выборка из sys.sequences (только поля, которые хранят параметры нашей последовательности):




  • start_value - Стартовое значение для объекта последовательности. Если объект последовательности перезапускается с помощью инструкции ALTER SEQUENCE, он начинается с этого значения. Когда объект последовательности выходит на следующий круг, он начинается с minimum_value или maximum_value, а не с start_value.
  • increment - Значение, на которое увеличивается значение объекта последовательности после каждого созданного значения.
  • minimum_value - Минимальное значение, возвращаемое объектом последовательности. По достижении этого значения объект последовательности либо возвращает ошибку при попытке создать дополнительные значения, либо перезапускается, если для него указан параметр CYCLE. Если параметр MINVALUE не задан, этот столбец возвращает минимальное значение, допустимое типом данных генератора последовательности.
  • maximum_value - Максимальное значение, возвращаемое объектом последовательности. По достижении этого значения объект последовательности либо начинает возвращать ошибку при попытке создать дополнительные значения, либо перезапускается, если для него указан параметр CYCLE. Если параметр MAXVALUE не задан, этот столбец возвращает максимальное значение, допустимое типом данных объекта последовательности.
  • is_cycling - Возвращает значение 0, если для объекта последовательности указан параметр NO CYCLE, и 1, если указан параметр CYCLE.
  • is_cached - Возвращает значение 0, если для объекта последовательности указан параметр NO CACHE, и 1, если указан параметр CACHE.
  • cache_size - Возвращает заданный размер кэша для объекта последовательности. Этот столбец содержит значение NULL, если последовательность была создана с параметром NO CACHE или был указан параметр CACHE без указания размера кэша. Если значение cache_size больше максимального числа значений, которые может возвращать объект последовательности, все равно показывается такой недостижимый размер кэша.
  • system_type_id - Идентификатор системного типа для типа данных объекта последовательности.
  • user_type_id - Определенный пользователем идентификатор типа данных для объекта последовательности.
  • precision - Максимальная точность типа данных.
  • scale - Максимальный масштаб типа данных. Масштаб возвращается вместе с точностью для предоставления пользователю полных метаданных.Масштаб объектов последовательности всегда равен 0, поскольку для них допустимы только целочисленные типы.
  • current_value - Последнее предоставленное значение. Это значение, возвращенное в результате последнего выполнения функции NEXT VALUE FOR, или последнее значение при выполнении процедуры sp_sequence_get_range. Если последовательность не использовалась, возвращается значение START WITH.
  • is_exhausted - 0 указывает, что последовательность еще может предоставлять новые значения. 1 указывает, что объект последовательности достиг значения MAXVALUE и для последовательности не задан параметр CYCLE. Функция NEXT VALUE FOR будет возвращать ошибку, пока последовательность не будет перезапущена с помощью инструкции ALTER SEQUENCE.


Создадим последовательность указав явный тип tinyint
create sequence dbo.seq02 as tinyint
т.к. tinyint - это диапазон от 0 до 255, то наша последовательность будет, как раз в этом диапазоне.

Создадим таблицу и попробуем наполнить её последовательностью с помощью sequence dbo.seq02.
--Тестовая таблица
create table dbo.TestTable01 ( i tinyint, val varchar(20) )
go
--Вставка одной записи
insert into dbo.TestTable01
values ( next value for dbo.seq02, 'Val01' )
go
--Вставка нескольких записей
insert into dbo.TestTable01
values ( next value for dbo.seq02, 'Val02' )
     , ( next value for dbo.seq02, 'Val03' )
     , ( next value for dbo.seq02, 'Val04' )
go
--Выборка из таблицы
select * from dbo.TestTable01



Теперь посмотрим, какие параметры имеет наша последовательность dbo.seq02:
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq02', 'SO' )



Теперь попробуем создать новую последовательность, задав при этом явно стартовое значение, инкремент, минимальное и максимальное значение:
create sequence dbo.seq03 as tinyint
  start with 10  --Начинаем с 10
  increment by 5 --Приращение = 5
  minvalue 5     --Минимум последовательности
  maxvalue 100   --Максимум последовательности
go  
--Посмотрим параметры нашей новой последовательности:
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq03', 'SO' )



Заполним новую таблицу несколькими значениями последовательности dbo.seq03:
--Тестовая таблица
create table dbo.TestTable02 ( i tinyint, val varchar(20) )
go
--Вставка нескольких записей
insert into dbo.TestTable02
values ( next value for dbo.seq03, 'Val01' )
     , ( next value for dbo.seq03, 'Val02' )
     , ( next value for dbo.seq03, 'Val03' )
go
--Выборка из таблицы
select * from dbo.TestTable02



В следующем примере я создам новую таблицу и присвою одному из её полей в качестве значения по умолчанию последовательность dbo.seq03 (некий аналог поля со свойством IDENTITY)
--Тестовая таблица
create table dbo.TestTable03 ( i tinyint default next value for dbo.seq03, val varchar(20) )
go
--Вставка нескольких записей
insert into dbo.TestTable03 ( val )
values ( 'Val01' )
     , ( 'Val02' )
     , ( 'Val03' )
go
--Выборка из таблицы
select * from dbo.TestTable03



Мы описали все основные параметры последовальностей, но остались ещё два ключевых параметра - это параметр [ CYCLE | NO CYCLE ] и [ CACHE [ ] | NO CACHE ].

[ CYCLE | NO CYCLE ] - параметр очень важный, т.к. именно он позволяет задать цикличность нашей последовательности, т.к. по умолчанию значение NO CYCLE и при достижении максимального значения наша последовательность не сможет сгенерировать новое значение, в результате ошибка:
Msg 11728, Level 16, State 1, Line 1 The sequence object 'seq03' has reached its minimum or maximum value. Restart the sequence object to allow new values to be generated.

Для "перезапуска" нашей последовательности необходимо выполнить скрипт:
alter sequence dbo.seq03 restart with 10 
Именно для того, чтобы не делать "перезапуск" последовательности руками, мы используем параметр CYCLE. Учтите, что циклическое повторение начинается не с начального, а с минимального или максимального (если последовательность отрицательная) значения.
create sequence dbo.seq04 as tinyint
  start with 20  --Начинаем с 20
  increment by 10 --Приращение = 5
  minvalue 0     --Минимум последовательности
  maxvalue 50   --Максимум последовательности
  cycle
go  
--Тестовая таблица
create table dbo.TestTable04 ( i tinyint, val varchar(20) )
go
--Вставка записей
insert into dbo.TestTable04
values ( next value for dbo.seq04, 'Val01' )
     , ( next value for dbo.seq04, 'Val02' )
     , ( next value for dbo.seq04, 'Val03' )
     , ( next value for dbo.seq04, 'Val04' )
     , ( next value for dbo.seq04, 'Val05' )
     , ( next value for dbo.seq04, 'Val06' )
     , ( next value for dbo.seq04, 'Val07' )
     , ( next value for dbo.seq04, 'Val08' )
     , ( next value for dbo.seq04, 'Val09' )
     , ( next value for dbo.seq04, 'Val10' )
go
select * from dbo.TestTable04



Последний параметр - это [ CACHE [ ] | NO CACHE ]

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

Например, если выбран размер кэша 50, то SQL Server не кэширует 50 отдельных значений. Кэшируется только текущее значение и число значений, оставшихся в кэше. Это значит, что объем памяти для хранения кэша всегда равен размеру двух экземпляров типа данных объекта последовательности.

Если параметр кэширования задан без указания размера кэша, то размер выбирается компонентом Database Engine. Однако пользователям не следует полагаться на предсказуемость выбора. Microsoft может изменить этот метод вычисления размера кэша без предварительного уведомления.

Если создание проводилось с параметром CACHE, то непредвиденное завершение работы (например, сбой электропитания) может привести к потере порядковых номеров, оставшихся в кэше.

Говоря о последовательностях, нельзя не упомянуть о функции sp_sequence_get_range, которая позволяет получить несколько значений из последовательности за один раз.
Синтаксис:
sp_sequence_get_range [ @sequence_name = ] N'' 
     , [ @range_size = ] range_size
     , [ @range_first_value = ] range_first_value OUTPUT 
    [, [ @range_last_value = ] range_last_value OUTPUT ]
    [, [ @range_cycle_count = ] range_cycle_count OUTPUT ]
    [, [ @sequence_increment = ] sequence_increment OUTPUT ]
    [, [ @sequence_min_value = ] sequence_min_value OUTPUT ]
    [, [ @sequence_max_value = ] sequence_max_value OUTPUT ]
    [ ; ]

Аргументы:
  • [ @sequence_name = ] N'sequence'
    Имя объекта последовательности.Схема является необязательной.Аргумент sequence_name имеет тип nvarchar(776).
  • [ @range_size = ] range_size
    Количество получаемых из последовательности значений. @range_size — bigint.
  • [ @range_first_value = ] range_first_value
    Необязательный выходной параметр возвращает первое (минимальное или максимальное) значение объекта последовательности, используемое для вычисления запрошенного диапазона. @range_first_value — sql_variant с тем же базовым типом, что и у объекта последовательности, примененного в запросе.
  • [ @range_last_value = ] range_last_value
    Необязательный выходной параметр возвращает последнее значение запрашиваемого диапазона. @range_last_value — sql_variant с тем же базовым типом, что и у объекта последовательности, примененного в запросе.
  • [ @range_cycle_count = ] range_cycle_count
    Необязательный выходной параметр возвращает количество циклов объекта последовательности, которое потребовалось для возврата запрошенного диапазона. @range_cycle_count — int.
  • [ @sequence_increment = ] sequence_increment
    Необязательный выходной параметр возвращает приращение объекта последовательности, которое использовалось для вычисления запрошенного диапазона. @sequence_increment — sql_variant с тем же базовым типом, что и у объекта последовательности в запросе.
  • [ @sequence_min_value = ] sequence_min_value
    Необязательный выходной параметр возвращает минимальное значение объекта последовательности. @sequence_min_value — sql_variant с тем же базовым типом, что и у объекта последовательности в запросе.
  • [ @sequence_max_value = ] sequence_max_value
    Необязательный выходной параметр возвращает максимальное значение объекта последовательности. @sequence_max_value — sql_variant с тем же базовым типом, что и у объекта последовательности в запросе.

Пример:
if object_id ( 'dbo.seq05', 'SO' ) is not null
drop sequence dbo.seq05
go
--Создадим новую последовательность
create sequence dbo.seq05 as tinyint
  start with 1   --Начинаем с 20
  increment by 1 --Приращение = 5
  minvalue 1     --Минимум последовательности
  maxvalue 200    --Максимум последовательности
  cycle
go  
--Посмотрим начальные параметры на нашей новой последовательности:
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq05', 'SO' )
--объявляем необходимые параметры для процедуры sp_sequence_get_range
declare @sequence_name nvarchar(100) = N'dbo.seq05'
      , @range_size int = 100
      , @range_first_value sql_variant
      , @range_last_value sql_variant
      , @sequence_increment sql_variant
      , @sequence_min_value sql_variant
      , @sequence_max_value sql_variant
-- запускаем процедуру sp_sequence_get_range
exec sp_sequence_get_range @sequence_name = @sequence_name
                        ,  @range_size = @range_size
                        ,  @range_first_value = @range_first_value output
                        ,  @range_last_value = @range_last_value output
                        ,  @sequence_increment = @sequence_increment output
                        ,  @sequence_min_value = @sequence_min_value output
                        ,  @sequence_max_value = @sequence_max_value output
-- показываем значения
select @range_size as [range_size]
     , @range_first_value as [range_first_value]
     , @range_last_value as [range_last_value]
     , @sequence_increment as [sequence_increment]
     , @sequence_min_value as [sequence_min_value]
     , @sequence_max_value as [sequence_max_value]
--Посмотрим текущие параметры на нашей последовательности:
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq05', 'SO' )



Ещё одна особенность последовательностей - это их работя в связке с предложением OVER
if object_id ( 'dbo.seq06', 'SO' ) is not null
drop sequence dbo.seq06
go
create sequence dbo.seq06 as tinyint
go  
if object_id ( 'dbo.TestTable05', 'U' ) is not null
drop table dbo.TestTable05
go
--Тестовая таблица
create table dbo.TestTable05 ( i tinyint, val varchar(20) )
go
--Вставка записей
insert into dbo.TestTable05
values ( next value for dbo.seq06, 'Val01' )
     , ( next value for dbo.seq06, 'Val02' )
     , ( next value for dbo.seq06, 'Val03' )
     , ( next value for dbo.seq06, 'Val04' )
     , ( next value for dbo.seq06, 'Val05' )
     , ( next value for dbo.seq06, 'Val06' )
     , ( next value for dbo.seq06, 'Val07' )
     , ( next value for dbo.seq06, 'Val08' )
     , ( next value for dbo.seq06, 'Val09' )
     , ( next value for dbo.seq06, 'Val10' )
go
--Значения у нашей последовательности
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq06', 'SO' )

--Использование последовательности в предложении OVER(!)
select *, next value for dbo.seq06 over (order by val desc) as [Order] 
from dbo.TestTable05
order by i

--Смотрим, как изменились значения у нашей последовательности
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq06', 'SO' )




Транзакции и Sequence

Так же, как и identity последовательности не "откатываю" свои значения, если транзакция была откачена, т.е. создаются "дырки".
if object_id ( 'dbo.seq07', 'SO' ) is not null
drop sequence dbo.seq07
go
create sequence dbo.seq07 as tinyint
go  
if object_id ( 'dbo.TestTable07', 'U' ) is not null
drop table dbo.TestTable07
go
--Тестовая таблица
create table dbo.TestTable07 ( i tinyint, val varchar(20) )
go

--Вставка записей в транзакции
begin tran
insert into dbo.TestTable07
values ( next value for dbo.seq07, 'Val01' )
     , ( next value for dbo.seq07, 'Val02' )
     , ( next value for dbo.seq07, 'Val03' )
go
rollback tran

--Значения у нашей последовательности
select start_value
     , increment
     , minimum_value
     , maximum_value
     , current_value
  from sys.sequences
  where object_id = object_id ( 'dbo.seq07', 'SO' )



Как видно на рисунке, не смотря на то, что транзакция была откачена, текущее значение последовательности не сбросилось на ноль.
В целом Sequence и Identity очень похожи, но и есть ряд отличий:
  • Identity - часть таблицв, а Sequence – объект БД
  • В отличии от Identity у Sequence можно определять границы значений
  • С помощью sp_sequence_get_range можно получить последовательность, что невозможно с Identity
  • Цикличность значений можно задать так же только для Sequence


Кроме того, в производительности Sequence значительно выигрывает у Identity



Более подробно об этом тесте можно прочитать в блоге Aaron Bertrand - http://sqlblog.com/blogs/aaron_bertrand/archive/2010/11/11/sql-server-11-denali-using-sequence.aspx

Ограничения использования Next Value для функций
Sequence ни в каких случаях нельзя использовать в сочетании с:

  • Проверкой ограничений (constraints)
  • Значениями по умолчанию
  • Вычисляемыми колонками
  • Представлениями (views)
  • Пользовательскими функциями
  • Пользовательскими функциями агрегации
  • Подзапросами
  • СТЕ (Common Table Expression)
  • Подтаблицами
  • Выражением TOP
  • Выражением Over
  • Выражением Output
  • Выражением On
  • Выражением Where
  • Выражением Group By
  • Выражением Having
  • Выражением Order By
  • Выражением Compute
  • Выражением Compute By




Ссылки по теме:

Tags: ,

SQL Server

Добавить комментарий

  Country flag

biuquote
  • Комментарий
  • Предпросмотр
Loading