Каков жизненный цикл интеграции SQL Server CLR?

Как объекты CLR (.NET) управляются в SQL Server?

Точка входа в любой код CLR из SQL Server — это статический метод. Обычно вы будете создавать только те объекты, которые существуют в рамках этого метода. Однако вы могли бы хранить ссылки на объекты в статических членах, позволяя им выйти из области вызова метода. Если SQL Server сохраняет эти объекты в памяти при нескольких вызовах хранимых процедур/функций, то они могут быть полезны для кэширования приложений, хотя и более опасны.

Как SQL Server обрабатывает это? Разрешает ли он даже (не метод) статические члены? Если да, то как долго он сохраняет их в памяти? Собирает ли он мусор после каждого вызова CLR? Как он обрабатывает параллелизм?


person Craig Walker    schedule 19.03.2009    source источник


Ответы (5)


В «Сборках Pro SQL Server 2005» Робина Дьюсона и Джулиана Скиннера говорится, что «Сборки, загруженные в базу данных, как и другие объекты базы данных, принадлежат пользователю базы данных. Все сборки, принадлежащие одному и тому же пользователю в одной базе данных, будут работать в одном домене приложения. Сборки, принадлежащие другому пользователю, будут выполняться в отдельном домене приложения».

Это говорит мне о том, что если вы работаете с одной базой данных и все сборки, которые вы загружаете с помощью оператора CREATE ASSEMBLY, имеют одного и того же владельца, то все ваши сборки будут работать в одном и том же домене приложения. Однако нахождение в одном и том же AppDomain не означает использование одной и той же кодовой базы, поэтому даже одна и та же dll может быть загружена в одни и те же домены приложений несколько раз, и ее типы не будут совпадать, даже если они имеют одно и то же имя. Когда типы с одинаковыми именами относятся к разным базам кода, их статические переменные также будут разными экземплярами.

Единственный способ безопасного использования статических переменных в среде SQL Server CLR с несколькими сборками — это просто использовать одну сборку. Вы можете использовать утилиту ILMerge с опцией «UnionMerge», чтобы упаковать все свои сборки в одну и объединить классы с одинаковым именем. Это должно гарантировать, что для данной базы данных в вашей единственной сборке ваши статические переменные будут работать так же, как и в автономном приложении. Я думаю, можно с уверенностью предположить, что домен приложения не выгружается и не перезагружается при каждом запросе, но вы не можете полагаться на то, что он никогда не будет выгружен, поскольку это произойдет всякий раз, когда возникает необработанная ошибка (по крайней мере, если он работает в небезопасном режиме ).

person Triynko    schedule 28.10.2009

SQL Server допускает статические члены только для чтения, если сборка развернута с уровнем разрешений Unsafe.

Практически объекты сохраняются в памяти до тех пор, пока служба SQL не будет остановлена/перезапущена.

Что касается параллелизма, ваш объект и методы должны быть потокобезопасными, как и везде.

Например:

public static class MyCLRClass
{
    private static readonly ReaderWriterLock rwlock = new ReaderWriterLock();
    private static readonly ArrayList list = new ArrayList();

    private static void AddToList(object obj)
    {
        rwlock.AcquireWriterLock(1000);
        try
        {
            list.Add(obj);
        }
        finally
        {
            rwlock.ReleaseLock();
        }
    }

    [SqlProcedure(Name="MyCLRProc")]
    public static void MyCLRProc()
    {
        rwlock.AcquireReaderLock(1000);
        try
        {
            SqlContext.Pipe.Send(string.Format("items in list: {0}", list.Count));
        }
        finally
        {
            rwlock.ReleaseLock();
        }
    }
}

Я использую такие вещи в SQL CLR, и это работает.

person Viktor Jevdokimov    schedule 28.08.2009

Не исключено; вы очень можете создавать статические элементы. НО, они должны быть помечены как readonly для сборок, которые имеют PERMISSION_SET из SAFE или EXTERNAL_ACCESS. Только сборка, помеченная как UNSAFE, может иметь статические элементы с возможностью записи. И это ограничение связано с самой природой статических членов: они общие совместно используются потоками и сеансами.

Сборка загружается при первом доступе к методу внутри нее. Он является общим для всех сеансов, поэтому доступны только статические методы. Идея состоит в том, чтобы писать функции, а не приложение, поэтому в сохранении состояния не так уж много пользы. И это может легко (хотя, конечно, не всегда) привести к непредсказуемому поведению, если различные сеансы перезаписывают друг друга. Таким образом, параллелизм вообще не обрабатывается, если только вы сами не напишете эту часть.

Следует ожидать, что после загрузки класс (и домен приложения, в котором он находится) останется в памяти до перезапуска службы SQL Server или изменения значения PERMISSION_SET. Но это не гарантируется. Согласно этой странице, Использование памяти в SQL CLR:

при нехватке памяти на сервере SQL CLR попытается освободить память, явно запустив сборку мусора и, при необходимости, выгрузив домены приложений.

Итак, вы правы в обоих случаях относительно статических членов:

  • их можно использовать для кеширования (очень круто)
  • they can be more dangerous:
    • they can cause unexpected behavior
    • они могут связывать память, поскольку нет внутреннего механизма или естественного события, чтобы очистить их, потому что класс остается активным.

Кроме того, объем памяти, доступной для подпрограмм CLR, сильно различается в зависимости от того, является ли SQL Server 32- или 64-разрядным, а также от того, используете ли вы SQL Server 2005/2008/2008 R2 или SQL Server 2012/2014. памяти SQLCLR, проверьте память SQL Server 2012 и Использование памяти в SQL CLR (такое же, как первую ссылку, размещенную над цитатой).

person Solomon Rutzky    schedule 05.12.2014

Вот некоторая информация, которую я нашел.

Проблемы с общим состоянием и анонимными делегатами в SQLCLR

Мало того, что общее состояние не разрешено в небезопасной сборке, но анонимные делегаты (к сожалению) запускают это ограничение «общего состояния».

person Craig Walker    schedule 19.03.2009

Из спецификации C# 3.0 (5.1.1)

Статическая переменная возникает перед выполнением статического конструктора (§10.12) для содержащего ее типа и прекращает свое существование, когда соответствующий домен приложения перестает существовать.

Конечно, он не собирается закрывать весь домен приложения после каждого вызова, поскольку это было бы немного неэффективно. Так что да, эти статические объекты остаются там до тех пор, пока база данных не будет остановлена ​​или перезапущена.

person Tamas Czinege    schedule 19.03.2009
comment
Я бы надеялся, что нет, но хотел бы увидеть однозначное «да» или «нет» специально для SQL Server (который определенно более ограничен, чем типичная среда выполнения .NET) - person Craig Walker; 19.03.2009
comment
@CraigWalker и Тамас: Что касается утверждения о том, что эти статические объекты остаются там до тех пор, пока база данных не останавливается или не перезапускается, это неверно. AppDomains могут быть выгружены по разным причинам, в том числе: 1) автоматически из-за нехватки памяти, 2) при изменении настроек безопасности сборки или базы данных, 3 ) если кто-то выполнит DBCC DROPSYSTEMBUFFERS('ALL'), и 4) может быть 1 или 2 другими способами. - person Solomon Rutzky; 11.07.2015