我们有问题设置并清除会话上下文值。
我们收到以下错误: The value was not set for key X because the total size of keys and values in the session context would exceed the 1 MB limit
我们正在使用ASP.NET Core和Dapper来访问数据。
打开连接时,我们执行sp_set_session_context
并发送4个键。3是整数和1个字符串。
在测试字符串时为空,整数小于10。
执行SQL命令后,我们将会话上下文值设置为NULL,关闭和处置连接。
我们正在使用以下查询来查看内存用法: SELECT SUM([pages_kb])
FROM [sys].[dm_os_memory_cache_counters]
WHERE [type] = 'CACHESTORE_SESSION_CONTEXT'
该查询尚未超过1MB。
有人知道我们为什么会收到此错误吗?
这是一个已知的错误,已在SQL Server 2016和2017中修复。以下脚本将可靠地重现:
bool unset = true;
using (var command = new SqlCommand()) {
command.CommandText = "sp_set_session_context";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("@key", SqlDbType.NVarChar, 128);
command.Parameters.Add("@value", SqlDbType.Variant, -1);
for (int cycles = 0; cycles != 10; ++cycles) {
++cycles;
using (var connection =
new SqlConnection(@"Data Source=(localdb)MSSqlLocalDB;Integrated Security=SSPI")
) {
connection.Open();
// Set as many values as we can
int keys = 0;
while (true) {
command.Connection = connection;
command.Parameters["@key"].Value = keys.ToString();
command.Parameters["@value"].Value = new String(' ', 8000);
try {
command.ExecuteNonQuery();
++keys;
} catch (SqlException e) {
Console.WriteLine("Failed setting at {0}: {1}", keys, e.Message);
break;
}
}
if (unset) {
// Now unset them
for (; keys >= 0; --keys) {
command.Connection = connection;
command.Parameters["@key"].Value = keys.ToString();
command.Parameters["@value"].Value = DBNull.Value;
try {
command.ExecuteNonQuery();
} catch (SqlException e) {
Console.WriteLine("Failed unsetting at {0}: {1}", keys, e.Message);
break;
}
}
}
}
}
}
输出:
在125处设置失败的设置:键'125'未设置该值,因为会话上下文中的密钥和值的总大小将超过1 MB限制。
在120处的设置失败设置:未为键'120'设置该值,因为会话上下文中的键和值的总大小将超过1 MB的限制。
在115处的设置失败设置:未为键'115'设置值,因为会话上下文中的键和值的总大小将超过1 MB的限制。
在110处的设置失败设置:未设置为键'110'的值,因为会话上下文中的键和值的总大小将超过1 MB限制。
在105处的设置失败:未设置值'105'的值,因为会话上下文中的键和值的总大小将超过1 MB的限制。
可用的上下文大小随着每个周期而减小。如果持续了足够长的时间,它将下降到一些最小值(不一定是0(。在这一点上,查询sys.dm_os_memory_cache_counters
表明使用的少于1 MB,但即使如此,也无法设置会话上下文。
此错误已在SQL Server 2016 SP1 CU8和SQL Server 2017 Cu6中修复。(修复程序会提到如果您使用键参数的 NULL
值清除内存问题,但是首先不允许使用键的 NULL
值,即使在较旧的版本。根据我的测试,它已被修复用于不设置 value 。(
对于先前的版本,至少有两个解决方法:
- 完成后,请勿将值设置为
NULL
,请留出引擎清除它们。在上面的脚本中,如果将unset
设置为false
,则不会观察到不会泄漏会话上下文。 - 使用非
NULL
前哨值来标记"删除"值,就像一个空字符串一样。