Sequência - NO CACHE vs CACHE 1

25

Existe alguma diferença entre um SEQUENCEdeclarado usando NO CACHEe um declarado usando CACHE 1no SQL Server 2012+?

Sequência # 1:

CREATE SEQUENCE dbo.MySeqCache1
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    CACHE 1;
GO

Sequência # 2:

CREATE SEQUENCE dbo.MySeqNoCache
AS INT
    START WITH 1
    INCREMENT BY 1
    MINVALUE 1
    MAXVALUE 9999
    NO CYCLE
    NO CACHE;
GO

Existe alguma diferença entre os dois? Eles se comportarão de maneira diferente ao serem usados ​​em um ambiente SQL Server 2012+?

marc_s
fonte

Respostas:

24

É difícil dar uma resposta definitiva a essa pergunta até que você realmente encontre a diferença. Não encontrei nenhum, mas isso não significa que não haja diferença, apenas porque não vi nenhum nos testes que fiz.

O teste fácil é para desempenho. Obter o próximo valor em um loop ou usar uma tabela de números como fonte para gerar vários valores por vez. Nos meus testes, não houve diferença no desempenho entre o uso de nenhum cache e um cache de 1 valor, mas houve uma melhoria significativa no desempenho do uso de um cache de 2.

Este é o código que eu usei para testar o desempenho:

declare @D datetime = getdate();

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

select datediff(millisecond, @D, getdate());

Resultado:

Cache        Time(ms)
------------ --------
NO CACHE     1200
1            1200
2             600
1000           70  

Para aprofundar um pouco, usei os eventos estendidos sqlserver.metadata_persist_last_value_for_sequencee sqlserver.lock_acquiredpara ver se havia algo diferente em como os valores persistem na tabela do sistema.

Usei esse código para testar se não há cache e tamanho de cache 1 e 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;

Não há diferença na saída para não usar cache e cache 1.

Saída de amostra:

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

Ao usar um cache de 4.

name                                      persisted_value mode
----------------------------------------- --------------- -----
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            IX
lock_acquired                             NULL            U
metadata_persist_last_value_for_sequence  4               NULL
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            SCH_S
lock_acquired                             NULL            IX
lock_acquired                             NULL            U
metadata_persist_last_value_for_sequence  8               NULL

O SCH_Sbloqueio é feito quando um valor é necessário. E quando o cache está esgotado, é seguido por um IXe um Ubloqueio e, finalmente, o evento metadata_persist_last_value_for_sequenceé acionado.

Portanto, não deve haver diferença entre usar nenhum cache ee cache 1 quando se trata de potencialmente perder valores em um desligamento inesperado do SQL Server.

Finalmente, notei algo na guia Mensagem no SSMS ao criar uma sequência com o cache 1.

O tamanho do cache para o objeto de sequência 'dbo.S' foi definido como NO CACHE.

Então, o SQL Server acha que não há diferença e me diz isso. No entanto, há uma diferença na sys.sequencescoluna cache_size. É NULL para nenhum cache e 1 para um cache de 1.

Mikael Eriksson
fonte