Tout savoir sur SEQUENCE avec SQL Server 2012

SEQUENCE et son CACHE

Comme on l’a vu auparavant, il est possible d’instruire SQL Server d’utiliser une cache pour les valeurs de SEQUENCE, et également d’en spécifier la taille.
L’avantage est bien sûr la possibilité d’augmenter les performances en diminuant les écritures dans les tables internes supportant l’implémentation de SEQUENCE.
Notons au passage que la taille du cache d’IDENTITY est 10 et il est impossible d’en changer. En revanche, celle de SEQUENCE est de 50 par défaut, et l’utilisateur peut la changer.

Je ne rentre pas plus dans les détails du fonctionnement du cache de SEQUENCE, qui sont décrits en détails dans l’aide, dans la section Remarques d’Ordre Général / Gestion du cache

On peut s’intéresser aux performances entre IDENTITY et SEQUENCE, en faisant varier la taille du cache de cette dernière. J’ai effectué sur ces tests sur mon ordinateur personnel, qui n’a donc rien à voir avec la configuration hardware d’un serveur dédié à SQL Server pour de l’OLTP. Il est donc évident que la concurrence à la génération des nombres n’entre ici pas en ligne de compte.
Les mesures doivent donc être bien au-delà ce que l’on obtiendrait sur un tel serveur; le but est seulement illustratif. Les tests on été effectués après un redémarrage de l’ordinateur, où seul SQL Server s’exécutait.

Voici le script :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
CREATE DATABASE sequence_performance_test
ON (NAME = sequence_performance_test_data, FILENAME = 'D:\SQL Server\sequence_performance_test.mdf', SIZE = 3GB)
LOG ON (NAME = sequence_performance_test_log, FILENAME = 'G:\SQL Server\sequence_performance_log.ldf', SIZE = 1GB)
GO

ALTER DATABASE sequence_performance_test
SET RECOVERY SIMPLE
GO

USE sequence_performance_test
GO

SET NOCOUNT ON
GO

CREATE TABLE dbo.nombre
(
        un_nombre bigint NOT NULL CONSTRAINT PK_nombre PRIMARY KEY
)
GO

CREATE TABLE identity_sequence
(
        identity_sequence bigint IDENTITY(1, 1)
)
GO

CREATE TABLE materialized_sequence
(
        materialized_sequence bigint NOT NULL
)
GO

INSERT  INTO dbo.materialized_sequence (materialized_sequence)
VALUES  (1)
GO

CREATE SEQUENCE dbo.une_sequence_bigint_without_cache
AS BIGINT
MINVALUE 1
NO MAXVALUE
START WITH 1
NO CACHE
GO

CREATE SEQUENCE dbo.une_sequence_bigint_cache_size_10
AS BIGINT
MINVALUE 1
NO MAXVALUE
START WITH 1
CACHE 10
GO

CREATE SEQUENCE dbo.une_sequence_bigint_cache_size_30
AS BIGINT
MINVALUE 1
NO MAXVALUE
START WITH 1
CACHE 30
GO

CREATE SEQUENCE dbo.une_sequence_bigint_cache_size_100
AS BIGINT
MINVALUE 1
NO MAXVALUE
START WITH 1
CACHE 100
GO

CREATE SEQUENCE dbo.une_sequence_bigint_cache_size_100000
AS BIGINT
MINVALUE 1
NO MAXVALUE
START WITH 1
CACHE 100000
GO

---------------------------------------------------------------------------
CREATE PROCEDURE usp_identity_sequence_get
        @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        DELETE  FROM dbo.identity_sequence

        INSERT  INTO dbo.identity_sequence DEFAULT VALUES

        SELECT  @_sequence_value = SCOPE_IDENTITY()
END
GO

CREATE PROCEDURE usp_materialized_sequence_get
        @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        UPDATE  dbo.materialized_sequence
        SET  @_sequence_value = materialized_sequence = materialized_sequence + 1
END
GO

CREATE PROCEDURE usp_sequence_bigint_without_cache_get
        @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        SELECT  @_sequence_value = NEXT VALUE FOR dbo.une_sequence_bigint_without_cache
END
GO

CREATE PROCEDURE usp_une_sequence_bigint_cache_size_10
        @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        SELECT  @_sequence_value = NEXT VALUE FOR dbo.une_sequence_bigint_cache_size_10
END
GO

CREATE PROCEDURE usp_une_sequence_bigint_cache_size_30
  @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        SELECT  @_sequence_value = NEXT VALUE FOR dbo.une_sequence_bigint_cache_size_30
END
GO

CREATE PROCEDURE usp_une_sequence_bigint_cache_size_100
  @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        SELECT  @_sequence_value = NEXT VALUE FOR dbo.une_sequence_bigint_cache_size_100
END
GO

CREATE PROCEDURE usp_une_sequence_bigint_cache_size_100000
  @_sequence_value bigint OUTPUT
AS
BEGIN
        SET NOCOUNT ON

        SELECT  @_sequence_value = NEXT VALUE FOR dbo.une_sequence_bigint_cache_size_100000
END
GO

---------------------------------------------------------------------------------------------
CREATE TABLE dbo.journal
(
        nom_test varchar(50) NOT NULL
        , dt_debut datetime NOT NULL
        , dt_fin datetime
)
GO
---------------------------------------------------------------------------------------------
INSERT INTO dbo.journal VALUES ('identity_sequence', GETDATE(), NULL)
GO

DECLARE @i bigint

EXEC dbo.usp_identity_sequence_get
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'identity_sequence'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('materialized_sequence', GETDATE(), NULL)
GO

DECLARE @i bigint
        , @dt_start datetime = GETDATE()

EXEC dbo.usp_materialized_sequence_get
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'materialized_sequence'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('sequence_bigint_without_cache', GETDATE(), NULL)
GO

DECLARE @i bigint
        , @dt_start datetime = GETDATE()

EXEC dbo.usp_sequence_bigint_without_cache_get
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'sequence_bigint_without_cache'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('sequence_bigint_cache_size_10', GETDATE(), NULL)
GO

DECLARE @i bigint
        , @dt_start datetime = GETDATE()

EXEC dbo.usp_une_sequence_bigint_cache_size_10
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'sequence_bigint_cache_size_10'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('sequence_bigint_cache_size_30', GETDATE(), NULL)
GO

DECLARE @i bigint
        , @dt_start datetime = GETDATE()

EXEC dbo.usp_une_sequence_bigint_cache_size_30
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'sequence_bigint_cache_size_30'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('sequence_bigint_cache_size_100', GETDATE(), NULL)
GO

DECLARE @i bigint
        , @dt_start datetime = GETDATE()

EXEC dbo.usp_une_sequence_bigint_cache_size_100
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'sequence_bigint_cache_size_100'

TRUNCATE TABLE dbo.nombre
GO

---
INSERT INTO dbo.journal VALUES ('sequence_bigint_cache_size_100000', GETDATE(), NULL)
GO

DECLARE @i bigint

EXEC dbo.usp_une_sequence_bigint_cache_size_100000
        @_sequence_value = @i OUTPUT

INSERT  INTO dbo.nombre VALUES (@i)
GO 100000

UPDATE  dbo.journal
SET     dt_fin = GETDATE()
WHERE   nom_test = 'sequence_bigint_cache_size_100000'

TRUNCATE TABLE dbo.nombre
GO

Voici donc les résultats :

Ce que Excel schématise comme suit :

Le gain de performance est donc significatif entre l’utilisation d’IDENTITY et l’utilisation d’une SEQUENCE avec mise en CACHE : près de 50 %. Même sans cette dernière, (cas sequence_bigint_without_cache), le gain est d’environ 30%.

En ce qui concerne les 3 derniers test avec une taille de cache de 30, 100 ou 100,000, je pense que j’ai été limité par la vitesse d’écriture dans le fichier du journal des transactions.

Si vous voulez effectuer le même test sur un vrai serveur et me donner les mesures par message privé, vous êtes bienvenus ;)

Laisser un commentaire