Архитектура интеграции со средой CLR — производительность

Применимо к: SQL Server Управляемый экземпляр SQL Azure

В этом разделе рассматриваются некоторые варианты проектирования, повышающие производительность интеграции Microsoft SQL Server с средой CLR microsoft платформа .NET Framework.

Процесс компиляции

При компиляции выражений SQL при обнаружении ссылки на управляемую подпрограмму создается заглушка MSIL. Эта заглушка содержит код для маршалинга параметров подпрограммы из SQL Server в среду CLR, вызова функции и возврата результата. Этот связующий код основан на типе параметра и его направлении (входной, выходной, передача по ссылке).

Код glue обеспечивает оптимизацию для конкретных типов и обеспечивает эффективное применение SQL Server семантики, например допустимость значений NULL, ограничение аспектов, по значению и стандартную обработку исключений. Создавая код для конкретных типов аргументов, можно избежать приведения типов и нагрузки по созданию объектов-оболочек (этот процесс называют также «упаковкой») при вызове, пересекающем границы процессов.

Затем созданная заглушка компилируется в машинный код и оптимизируется для конкретной аппаратной архитектуры, в которой выполняется SQL Server, с помощью JIT-служб компиляции среды CLR. JIT-службы вызываются на уровне метода и позволяют среде размещения SQL Server создать единую единицу компиляции, охватывающую SQL Server и выполнение среды CLR. После компиляции заглушки результирующий указатель на функцию становится реализацией этой функции времени выполнения. Такой подход к созданию кода гарантирует отсутствие лишних расходов по вызову функций, связанных с отражением или доступом к метаданным во время выполнения.

Быстрые переходы между СУБД SQL Server и средой CLR

Процесс компиляции возвращает указатель на функцию, с помощью которого можно вызвать функцию во время выполнения из машинного кода. Для определяемых пользователем скалярных функций этот вызов функции происходит по строкам. Чтобы свести к минимуму затраты на переход между SQL Server и средой CLR, инструкции, содержащие любой управляемый вызов, имеют шаг запуска для определения домена целевого приложения. Этот шаг идентификации снижает стоимость перехода для каждой строки.

Вопросы производительности

Ниже приведены рекомендации по производительности, относящиеся к интеграции со средой CLR в SQL Server. Более подробные сведения см. в разделе "Использование интеграции со средой CLR в SQL Server 2005" на веб-сайте MSDN. Общие сведения о производительности управляемого кода можно найти в разделе "Повышение производительности и масштабируемости приложений .NET" на веб-сайте MSDN.

Определяемые пользователем функции

Функции CLR выигрывают от более быстрого пути вызова, чем у определяемых пользователем функций Transact-SQL. Кроме того, управляемый код имеет решающее преимущество в производительности по сравнению с Transact-SQL с точки зрения процедурного кода, вычислений и операций со строками. Функции CLR, которые требуют большого объема вычислений и не требуют доступа к данным, лучше писать в управляемом коде. Однако функции Transact-SQL выполняют доступ к данным более эффективно, чем интеграция со средой CLR.

Определяемые пользователем статистические функции

Управляемый код может значительно опережать по производительности статическую обработку на основе курсора. Управляемый код обычно выполняется немного медленнее, чем встроенные агрегатные функции SQL Server. Если существует собственная встроенная агрегатная функция SQL Server, рекомендуется использовать ее. В случаях, когда нужные статистические вычисления не поддерживаются встроенными функциями, из соображений производительности можно использовать созданную пользователем статистическую функцию среды CLR, реализованную на основе курсора.

Функции потока с табличным значением

Часто бывает нужно, чтобы в результате вызова функции приложение вернуло таблицу. Например, в качестве части операции импорта приложение читает табличные данные из файла; нужно преобразовать их из формата величин с разделителями-запятыми в реляционное представление. Обычно это достигается с помощью материализации и заполнения таблицы результатов до ее использования вызывающим объектом. Интеграция среды CLR с SQL Server представляет новый механизм расширяемости, называемый потоковой функцией с табличным значением (STVF). Управляемые функции потока, возвращающие табличное значение, по производительности опережают реализации на основе расширенных хранимых процедур.

STVF — это управляемые функции, которые возвращают интерфейс IEnumerable . IEnumerable содержит методы для навигации по результирующем набору, возвращаемому STVF. При вызове STVF возвращенный объект IEnumerable напрямую подключается к плану запроса. План запроса вызывает методы IEnumerable , когда требуется получить строки. Такая модель итерации позволяет провести немедленную обработку результатов сразу после получения первой строки, не ожидая заполнения всей таблицы. Она также существенно снижает затраты памяти на вызов функции.

Сравнение массивов и курсоров

Если курсоры Transact-SQL должны проходить через данные, которые проще выразить в виде массива, управляемый код можно использовать со значительным повышением производительности.

Строковые данные

SQL Server символьные данные, такие как varchar, могут иметь тип SqlString или SqlChars в управляемых функциях. Переменные типа SqlString создают в памяти экземпляр всего значения целиком. Переменные типа SqlChars обеспечивают потоковый интерфейс, который позволяет добиться более высокой производительности и масштабируемости, так как не создает в памяти экземпляра всего значения сразу. Это особенно важно для типов больших объектов (LOB). Кроме того, доступ к XML-данным сервера можно получить через интерфейс потоковой передачи, возвращаемый SqlXml.CreateReader().

Сравнение CLR и расширенных хранимых процедур

API-интерфейсы Microsoft.SqlServer.Server, позволяющие управляемым процедурам отсылать результирующие наборы обратно клиенту, имеют более высокую производительность, чем API-интерфейсы служб Open Data Services (ODS), используемые расширенными хранимыми процедурами. Кроме того, API System.Data.SqlServer поддерживают такие типы данных, как xml, varchar(max), nvarchar(max) и varbinary(max), представленные в SQL Server 2005 (9.x), в то время как API ODS не были расширены для поддержки новых типов данных.

С помощью управляемого кода SQL Server управляет использованием ресурсов, таких как память, потоки и синхронизация. Это связано с тем, что управляемые API, предоставляющие эти ресурсы, реализуются поверх SQL Server resource manager. И наоборот, SQL Server не имеет представления или контроля над использованием ресурсов расширенной хранимой процедуры. Например, если расширенная хранимая процедура потребляет слишком много ресурсов ЦП или памяти, это невозможно обнаружить или контролировать с помощью SQL Server. Однако с помощью управляемого кода SQL Server может обнаружить, что данный поток не давался в течение длительного периода времени, а затем принудительно принудить задачу к получению, чтобы можно было запланировать другие работы. Поэтому использование управляемого кода позволяет лучше масштабировать выполнение и оптимизировать использование системных ресурсов.

Управляемый код может вызывать дополнительные расходы на поддержку среды выполнения и проверки безопасности. Это происходит, например, при выполнении внутри SQL Server и при необходимости выполнения многочисленных переходов с управляемого кода на машинный код (так как SQL Server необходимо выполнить дополнительное обслуживание параметров потока при переходе на машинный код и обратно). Следовательно, расширенные хранимые процедуры могут значительно превзойть управляемый код, выполняемый в SQL Server в случаях, когда часто происходит переход между управляемым и машинным кодом.

Примечание

Не рекомендуется разрабатывать новые расширенные хранимые процедуры, поскольку эта функциональная возможность устарела.

Собственная сериализация для определяемых пользователем типов

Определяемые пользователем типы (UDT) представляют собой механизм расширения скалярной системы типов. SQL Server реализует формат сериализации для определяемых пользователем типов с именем Format.Native. Во время компиляции исследуется структура типа, а затем создается код MSIL, настраиваемый для данного конкретного определения типа.

Собственная сериализация — это реализация по умолчанию для SQL Server. Сериализация, определяемая пользователем, вызывает для сериализации метод, указанный автором типа. Для достижения максимальной производительности следует использовать сериализацию Format.Native.

Нормализация сравнимых определяемых пользователем типов

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

Нормализация имеет два преимущества: ее использование значительно «удешевляет» операцию сравнения, так как избавляет от необходимости создания экземпляра типа и вызова метода; кроме того, нормализация создает двоичное представление определяемого пользователем типа, что позволяет строить гистограммы, индексы и гистограммы для значений этого типа. Поэтому производительность операций с нормализованными определяемыми пользователем типами почти такая же, как у операций, не требующих вызова методов, над встроенными типами.

Масштабируемое использование памяти

Чтобы управляемая сборка мусора выполнялись и масштабироваться в SQL Server, избегайте большого однократного выделения. Выделенные области памяти размером больше 88 КБ помещаются в кучу для больших объектов, для которой сборка мусора работает гораздо медленнее и хуже масштабируется, чем для небольших областей памяти. Например, если нужно выделить память для большого многомерного массива, лучше выделить память под массив массивов (разреженный массив).

См. также:

Определяемые пользователем типы CLR