序列 - 无缓存 vs 缓存 1

mar*_*c_s 25 sql-server sequence sql-server-2012

SQL Server 2012+ 中SEQUENCE声明的 usingNO CACHE和声明的 using之间有什么区别CACHE 1吗?

序列#1:

CREATE SEQUENCE dbo.MySeqCache1
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    CACHE 1;
GO
Run Code Online (Sandbox Code Playgroud)

序列#2:

CREATE SEQUENCE dbo.MySeqNoCache
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    NO CACHE;
GO
Run Code Online (Sandbox Code Playgroud)

两者之间有什么区别吗?在 SQL Server 2012+ 环境中使用时,它们的行为会有所不同吗?

Mik*_*son 24

在您真正找到差异之前,很难对这个问题给出明确的答案。我没有发现,但这并不意味着没有区别,只是我在所做的测试中没有看到。

简单的测试是性能。在循环中获取下一个值或使用数字表作为源一次生成多个值。在我的测试中,不使用缓存和缓存值为 1 的性能没有差异,但使用缓存值为 2 有显着的性能提升。

这是我用来测试性能的代码:

declare @D datetime = getdate();

declare @I int = 0;
while @I < 9999
  select @I = next value for dbo.S;

select datediff(millisecond, @D, getdate());
Run Code Online (Sandbox Code Playgroud)

结果:

Cache        Time(ms)
------------ --------
NO CACHE     1200
1            1200
2             600
1000           70  
Run Code Online (Sandbox Code Playgroud)

为了更深入地挖掘,我使用了扩展事件sqlserver.metadata_persist_last_value_for_sequencesqlserver.lock_acquired查看值在系统表中的持久化方式是否有所不同。

我使用此代码来测试无缓存和缓存大小为 1 和 4。

DECLARE @S NVARCHAR(max) = '
CREATE EVENT SESSION SeqCache ON SERVER 
ADD EVENT sqlserver.lock_acquired(
    WHERE (sqlserver.session_id=({SESSIONID}))),
ADD EVENT sqlserver.metadata_persist_last_value_for_sequence(
    WHERE (sqlserver.session_id=({SESSIONID}))) 
ADD TARGET package0.event_file(SET filename=N''d:\SeqCache'');';

SET @S = REPLACE(@S, '{SESSIONID}', CAST(@@SPID AS NVARCHAR(max)));

EXEC (@S);

GO

CREATE SEQUENCE dbo.S
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    NO CACHE;
--    CACHE 1;
--    CACHE 4;

GO

ALTER EVENT SESSION SeqCache ON SERVER STATE = START;

GO

DECLARE @I INT = 0;
WHILE @I < 10
  SELECT @I = NEXT VALUE FOR dbo.S;

GO

ALTER EVENT SESSION SeqCache ON SERVER STATE = STOP;
DROP EVENT SESSION SeqCache ON SERVER;
DROP SEQUENCE dbo.S;
Run Code Online (Sandbox Code Playgroud)

不使用缓存和缓存为 1 的输出没有区别。

示例输出:

DECLARE @S NVARCHAR(max) = '
CREATE EVENT SESSION SeqCache ON SERVER 
ADD EVENT sqlserver.lock_acquired(
    WHERE (sqlserver.session_id=({SESSIONID}))),
ADD EVENT sqlserver.metadata_persist_last_value_for_sequence(
    WHERE (sqlserver.session_id=({SESSIONID}))) 
ADD TARGET package0.event_file(SET filename=N''d:\SeqCache'');';

SET @S = REPLACE(@S, '{SESSIONID}', CAST(@@SPID AS NVARCHAR(max)));

EXEC (@S);

GO

CREATE SEQUENCE dbo.S
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    NO CACHE;
--    CACHE 1;
--    CACHE 4;

GO

ALTER EVENT SESSION SeqCache ON SERVER STATE = START;

GO

DECLARE @I INT = 0;
WHILE @I < 10
  SELECT @I = NEXT VALUE FOR dbo.S;

GO

ALTER EVENT SESSION SeqCache ON SERVER STATE = STOP;
DROP EVENT SESSION SeqCache ON SERVER;
DROP SEQUENCE dbo.S;
Run Code Online (Sandbox Code Playgroud)

当使用缓存为 4 时。

name                                      persisted_value mode
----------------------------------------- --------------- -----
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            IX
lock_acquired                             NULL            U
metadata_persist_last_value_for_sequence  1               NULL
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            IX
lock_acquired                             NULL            U
metadata_persist_last_value_for_sequence  2               NULL
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            IX
lock_acquired                             NULL            U
metadata_persist_last_value_for_sequence  3               NULL
Run Code Online (Sandbox Code Playgroud)

SCH_S需要的值时,锁就完成了。当缓存耗尽时,紧接着是 aIX和 aU锁,最后metadata_persist_last_value_for_sequence触发事件。

因此,在 SQL Server 意外关闭时可能丢失值时,不使用缓存和使用缓存 1 应该没有区别。

最后,在使用缓存 1 创建序列时,我在 SSMS 的“消息”选项卡中注意到了一些内容。

序列对象 'dbo.S' 的缓存大小已设置为 NO CACHE。

所以,SQL Server 认为没有区别并告诉我。然而sys.sequences,列中存在差异cache_size。无缓存时为 NULL,缓存为 1 时为 1。