【问题标题】:Select from sequence with SqlCommand.ExecuteScalar() returns NULL when high disk usage当磁盘使用率高时,使用 SqlCommand.ExecuteScalar() 从序列中选择返回 NULL
【发布时间】:2018-03-16 16:07:01
【问题描述】:

我在生产环境中遇到SqlCommand.ExecuteScalar() 有时会返回NULL

我在这里遇到过很多类似的问题,最接近的一个是:SqlCommand.ExecuteScalar returns null but raw SQL does not。但给出的建议与我的情况无关。

代码示例在这里:

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
    }
}

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

CREATE SEQUENCE [dbo].[Seq_Revision] 
 AS [bigint]
 START WITH 0
 INCREMENT BY 1
 MINVALUE -9223372036854775808
 MAXVALUE 9223372036854775807
 CACHE  10 
GO

而且我很确定它永远不会真正返回 NULL。


当在此代码示例中返回 NULL 时,我也观察到类似的奇怪(不可重复的行为),而我确定 存在具有此 ID 的实体:

NHibernate.ISession.Get<FooEntity>(entityId)

有趣的是,通过这种方法返回 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: )

【问题讨论】:

  • ExecuteScalar 返回null 表示:没有返回行。如果返回的行为空值,则为DBNull.Value。这没有回答“为什么?”,但它可能是有用的上下文
  • @MarcGravell,我知道。但是你相信 SELECT NEXT VALUE FOR Seq_Revision 返回 0 行吗?听起来不可能。
  • 我不知道;这是个好问题
  • NEXT VALUE FOR 不支持只读数据库。请参阅docs.microsoft.com/en-us/sql/t-sql/functions/… 的限制和限制 => 从连接字符串中删除 ApplicationIntent=READONLY
  • 您能否测试这种情况,例如if (command.GetType() == typeof(DBNull)) 或者它用InvalidCastException 捕获它,然后检查值或在Thread.Sleep(1000); 之后重试,以排除磁盘的计时问题.也是添加一些日志记录以帮助形成minimal reproducible example 的好地方,我猜它是间歇性的,并且只能在 IO 压力下重现。

标签: c# sql-server ado.net sql-server-2014 alwayson


【解决方案1】:

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

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

尝试禁用序列中的缓存:

ALTER SEQUENCE [dbo].[Seq_Revision] 
 NO CACHE
GO

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

ALTER SEQUENCE [dbo].[Seq_Revision] 
 CACHE 100
GO

【讨论】:

  • 谢谢,我们会试试这个理论。但这无法解释为什么我有时会从 ISession.Get(id) 获得 NULL,而我确信具有此 ID 的实体确实存在:NHibernate.ISession.Get(entityId)
  • ISession.Get 访问数据库或会话缓存以检索实体数据。如果实体存在则返回,否则返回 NULL。这意味着如果会话缓存存在未处理的问题.. 你可以得到 NULLs
猜你喜欢
  • 2018-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 2017-11-25
  • 2012-05-31
  • 2015-03-23
  • 1970-01-01
相关资源
最近更新 更多