Приветствую! При использовании sp_set_session_context/SESSION_CONTEXT на нашем продуктиве регулярно стала появляться ошибка (из сабжа).
При попытке её повторить выяснил как она появляется.
Если вызвать любой подобный "тепличный" код из Microsoft SQL Server Management Studio, то всё будет замечательно:
Но! Если это сделать вот таким кодом из клиента (пример на PowerShell для ясности), то легко добиться ошибки:
Ключевой момент: Для повторяемости ошибки должен быть вызов обнуления контекстной переменной отдельной командой! Первичное присвоение значения на ошибку не влияет. В реальности переменные присваиваются в процедурах, многие из них не очищать не могу :(
Проверял на
<= SQL Server 2016 (SP1-CU6) (KB4037354) - 13.0.4457.0
и SQL Server 2017 (RTM) - 14.0.1000.169
Похоже есть какая-то утечка в SQL Server при обнулении сессионных переменных :( Может кто-то знает как обойти эту беду?
Диагностические запросы, наподобие
При попытке её повторить выяснил как она появляется.
Если вызвать любой подобный "тепличный" код из Microsoft SQL Server Management Studio, то всё будет замечательно:
declare @context_debug nvarchar(4000) = replicate('Z', 2000), @i int = 0 while @i < 10000 begin set @i+=1 exec sp_set_session_context N'context_debug', @context_debug; exec sp_set_session_context N'context_debug', null; -- if @i % 1000 = 0 print concat(@i, ' @context_debug=', @context_debug) end print concat(@i, ' last context_debug=', cast(isNull(session_context(N'context_debug'), 'NULL') as nvarchar(4000)))
Но! Если это сделать вот таким кодом из клиента (пример на PowerShell для ясности), то легко добиться ошибки:
Clear-Host $ServerName = ".\SQL2017" $SqlConnection = New-Object system.data.SqlClient.SQLConnection("App=test-context;Server=$ServerName; Integrated Security=SSPI;Pooling=false"); $SqlCommand2 = New-Object System.Data.SqlClient.SqlCommand("exec sp_set_session_context N'context_debug', null;", $SqlConnection) try { $SqlConnection.Open(); for ($i = 1; $i -le 10000; $i++) { $r = $SqlCommand2.ExecuteNonQuery() if ($i % 1000 -eq 0) { Write-Host "i = $i; " -NoNewline -ForegroundColor Green } } } catch { Write-Host "ERROR Code = " -NoNewline -ForegroundColor Yellow Write-Host $_.Exception.InnerException.Number -ForegroundColor Yellow Write-Host $_.Exception.Message -ForegroundColor Red } finally { Write-Host "Last i = $i" -ForegroundColor Blue $SqlConnection.Close() $SqlConnection.Dispose() }
Результат из PS |
---|
i = 1000; i = 2000; ERROR Code = 15665 Исключение при вызове "ExecuteNonQuery" с "0" аргументами: "Значение ключа "context_debug" не было задано, так как общий размер ключей и значений в контексте сеанса превысил бы ограничение в 1 МБ." Last i = 2820 PS C:\Scripts> |
Ключевой момент: Для повторяемости ошибки должен быть вызов обнуления контекстной переменной отдельной командой! Первичное присвоение значения на ошибку не влияет. В реальности переменные присваиваются в процедурах, многие из них не очищать не могу :(
Проверял на
<= SQL Server 2016 (SP1-CU6) (KB4037354) - 13.0.4457.0
и SQL Server 2017 (RTM) - 14.0.1000.169
Похоже есть какая-то утечка в SQL Server при обнулении сессионных переменных :( Может кто-то знает как обойти эту беду?
Диагностические запросы, наподобие
SELECT * FROM sys.dm_os_memory_cache_counters WHERE type = 'CACHESTORE_SESSION_CONTEXT';никаких утечек не показывают :(