使用SqlCommand.ExecuteScalar()从序列中选择高磁盘使用时返回NULL

fla*_*am3 11 c# sql-server ado.net alwayson sql-server-2014

我有时会在生产环境中遇到这种SqlCommand.ExecuteScalar()情况NULL.

我在这里遇到了很多类似的问题,最接近的是:SqlCommand.ExecuteScalar返回null但原始SQL没有.但给出的建议与我的情况无关.

代码示例如下:

using (var connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (var command = connection.CreateCommand())
    {
        command.CommandText = "SELECT NEXT VALUE FOR Seq_Revision";
        command.CommandType = CommandType.Text;

        return (long)command.ExecuteScalar(); //<---ExecuteScalar() here returns NULL sometimes
    }
}
Run Code Online (Sandbox Code Playgroud)

Seq_Revision 这里是简单的MSSQL序列,如下所示:

CREATE SEQUENCE [dbo].[Seq_Revision] 
 AS [bigint]
 START WITH 0
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE  10 
GO
Run Code Online (Sandbox Code Playgroud)

而且我很确定它永远不会实际返回NULL.


我也观察到类似的怪(不可重复的行为)时,NULL该代码示例中返回,而我敢肯定有有这个ID的实体:

NHibernate.ISession.Get<FooEntity>(entityId)
Run Code Online (Sandbox Code Playgroud)

有趣的是,NULL通过此方法返回与SQL节点上磁盘活动较多(磁盘队列长度> ~50)时的时间帧相关联.

可能很重要:我们使用具有2个节点的AlwaysON群集,其中一个节点用于读取模式(ApplicationIntent=READONLY在连接字符串中).

MSSQL版本是:

Microsoft SQL Server 2014 (SP2-CU5) (KB4013098) - 12.0.5546.0 (X64) 
    Apr  3 2017 14:55:37 
    Copyright (c) Microsoft Corporation
    Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 <X64> (Build 9600: )
Run Code Online (Sandbox Code Playgroud)

Mtw*_*ark 2

我认为问题可能与序列缓存有关。

也许有一些未处理的事情导致缓存中剩余的序列号丢失。

尝试禁用序列中的缓存:

ALTER SEQUENCE [dbo].[Seq_Revision] 
 NO CACHE
GO
Run Code Online (Sandbox Code Playgroud)

或者尝试使用更高的缓存值:

ALTER SEQUENCE [dbo].[Seq_Revision] 
 CACHE 100
GO
Run Code Online (Sandbox Code Playgroud)