Существуют ли многопоточные механизмы кэширования, которые будут работать в функции CLR SQL, не требуя регистрации сборки как "небезопасной"?
Как также описано в этом сообщении, просто использование оператора lock
вызовет исключение в безопасной сборке:
System.Security.HostProtectionException:
Attempted to perform an operation that was forbidden by the CLR host.
The protected resources (only available with full trust) were: All
The demanded resources were: Synchronization, ExternalThreading
Я хочу, чтобы любые вызовы моим функциям использовали один и тот же внутренний кеш в потокобезопасной манере, так что многие операции могут выполнять кеширование и запись одновременно. По существу - мне нужен ConcurrentDictionary
, который будет работать в "безопасной" сборке SQLCLR. К сожалению, использование ConcurrentDictionary
само по себе дает то же исключение, что и выше.
Есть ли что-то встроенное в SQLCLR или SQL Server для обработки этого? Или я неправильно понимаю модель потоков SQLCLR?
Я прочитал столько, сколько могу найти о ограничениях безопасности SQLCLR. В частности, следующие статьи могут быть полезны для понимания того, о чем я говорю:
- Интеграция CLR SQL Server Часть 1: Безопасность
- Развертывание/использование сборок, требующих Unsafe/External Access с CLR и T-SQL
Этот код в конечном итоге будет частью библиотеки, которая будет распространена среди других, поэтому я действительно не хочу, чтобы ее запускали как "небезопасные".
Один из вариантов, который я рассматриваю (приведенный ниже в комментариях Spender), заключается в том, чтобы обратиться к tempdb из кода SQLCLR и использовать его как кеш. Но я не совсем точно знаю, как это сделать. Я также не уверен, будет ли он где-нибудь рядом с исполняемым файлом, как кеш в памяти. См. Обновление ниже.
Меня интересуют любые другие альтернативы, которые могут быть доступны. Спасибо.
Пример
В приведенном ниже коде используется статический параллельный словарь в виде кеша и доступ к этому кешу через пользовательские функции SQL CLR. Все вызовы функций будут работать с одним и тем же кешем. Но это не сработает, если сборка не зарегистрирована как "небезопасная".
public class UserDefinedFunctions
{
private static readonly ConcurrentDictionary<string,string> Cache =
new ConcurrentDictionary<string, string>();
[SqlFunction]
public static SqlString GetFromCache(string key)
{
string value;
if (Cache.TryGetValue(key, out value))
return new SqlString(value);
return SqlString.Null;
}
[SqlProcedure]
public static void AddToCache(string key, string value)
{
Cache.TryAdd(key, value);
}
}
Они находятся в сборке под названием SqlClrTest
и используют следующие оболочки SQL:
CREATE FUNCTION [dbo].[GetFromCache](@key nvarchar(4000))
RETURNS nvarchar(4000) WITH EXECUTE AS CALLER
AS EXTERNAL NAME [SqlClrTest].[SqlClrTest.UserDefinedFunctions].[GetFromCache]
GO
CREATE PROCEDURE [dbo].[AddToCache](@key nvarchar(4000), @value nvarchar(4000))
WITH EXECUTE AS CALLER
AS EXTERNAL NAME [SqlClrTest].[SqlClrTest.UserDefinedFunctions].[AddToCache]
GO
Затем они используются в базе данных следующим образом:
EXEC dbo.AddToCache 'foo', 'bar'
SELECT dbo.GetFromCache('foo')
UPDATE
Я понял, как получить доступ к базе данных из SQLCLR, используя Контекстное соединение. Код в этом Gist показывает как подход ConcurrentDictionary
, так и метод tempdb. Затем я провел несколько тестов со следующими результатами, полученными из статистики клиента (в среднем 10 проб):
Concurrent Dictionary Cache
10,000 Writes: 363ms
10,000 Reads : 81ms
TempDB Cache
10,000 Writes: 3546ms
10,000 Reads : 1199ms
Таким образом, возникает идея использования таблицы tempdb. Я действительно ничего не могу попробовать?