Производительность архитектуры интеграции СРЕДЫ CLR
Область применения: SQL Server Управляемый экземпляр SQL Azure
В этой статье рассматриваются некоторые варианты проектирования, которые повышают производительность интеграции SQL Server с средой clR (CLR) Microsoft платформа .NET Framework.
Процесс компиляции
Во время компиляции выражений SQL при обнаружении ссылки на управляемую подпрограмму создается заглушка промежуточного языка Майкрософт (MSIL). Эта заглушка включает код для маршалирования параметров подпрограммы из SQL Server в среду CLR, вызова функции и возврата результата. Этот связующий код основан на типе параметра и его направлении (входной, выходной, передача по ссылке).
Код клея обеспечивает оптимизацию с учетом типов и обеспечивает эффективное применение семантики SQL Server, например nullability, ограничение аспектов, по значению и стандартной обработке исключений. Создавая код для конкретных типов аргументов, можно избежать приведения типов и нагрузки по созданию объектов-оболочек (этот процесс называют также «упаковкой») при вызове, пересекающем границы процессов.
Затем созданная заглушка компилируется в машинный код и оптимизирован для конкретной аппаратной архитектуры, на которой выполняется SQL Server, используя службы JIT-компиляции среды CLR. Службы JIT вызываются на уровне метода и позволяют среде размещения SQL Server создать одну единицу компиляции, которая охватывает выполнение SQL Server и СРЕДЫ CLR. После компиляции заглушки результирующий указатель на функцию становится реализацией этой функции времени выполнения. Этот подход создания кода гарантирует отсутствие дополнительных затрат на вызов, связанных с отражением или доступом к метаданным во время выполнения.
Быстрые переходы между SQL Server и CLR
Процесс компиляции возвращает указатель на функцию, с помощью которого можно вызвать функцию во время выполнения из машинного кода. Для скалярных определяемых пользователем функций эта функция выполняется на основе каждой строки. Чтобы свести к минимуму затраты на переход между SQL Server и CLR, инструкции, содержащие любой управляемый вызов, имеют шаг запуска для идентификации домена целевого приложения. Этот шаг идентификации снижает стоимость перехода для каждой строки.
Замечания, связанные с быстродействием
В следующем разделе приведены рекомендации по повышению производительности, относящиеся к интеграции СРЕДЫ CLR в SQL Server. Дополнительные сведения см. в статье об использовании интеграции СРЕДЫ CLR в SQL Server 2005. Сведения о производительности управляемого кода см. в статье "Улучшение производительности приложений .NET и масштабируемость".
Пользовательские функции
Функции СРЕДЫ CLR получают более быстрый путь вызова, чем определяемые пользователем функции Transact-SQL. Кроме того, управляемый код имеет решающее преимущество производительности по сравнению с Transact-SQL с точки зрения процедурного кода, вычислений и строковых манипуляций. Функции СРЕДЫ CLR, которые являются вычислительными и не выполняют доступ к данным, лучше написаны в управляемом коде. Однако функции Transact-SQL выполняют доступ к данным более эффективно, чем интеграция СРЕДЫ CLR.
определяемые пользователем агрегатные функции;
Управляемый код может значительно опережать по производительности статическую обработку на основе курсора. Управляемый код обычно выполняет немного медленнее встроенных агрегатных функций SQL Server. Если существует собственная встроенная агрегатная функция SQL Server, рекомендуется использовать ее. В случаях, когда необходимая агрегатная обработка не поддерживается изначально, рассмотрите определяемую пользователем среду CLR агрегат по поводу реализации на основе курсоров по соображениям производительности.
Потоковая передача табличных функций
Часто бывает нужно, чтобы в результате вызова функции приложение вернуло таблицу. Например, в качестве части операции импорта приложение читает табличные данные из файла; нужно преобразовать их из формата величин с разделителями-запятыми в реляционное представление. Обычно это достигается с помощью материализации и заполнения таблицы результатов до ее использования вызывающим объектом. Интеграция СРЕДЫ CLR с SQL Server представляет новый механизм расширяемости, называемый функцией потоковой передачи с табличным значением (STVF). Управляемые функции потока, возвращающие табличное значение, по производительности опережают реализации на основе расширенных хранимых процедур.
Потоковые функции с табличными значениями — это управляемые функции, которые возвращают интерфейс IEnumerable
. У интерфейса IEnumerable
есть методы для навигации по результирующему набору, возвращенному потоковой функцией с табличными значениями. При вызове возвращающей табличное значение функции потока возвращенный интерфейс IEnumerable
непосредственно соединен с планом запроса. Когда плану запроса нужно получить строки, он вызывает методы интерфейса IEnumerable
. Такая модель итерации позволяет провести немедленную обработку результатов сразу после получения первой строки, не ожидая заполнения всей таблицы. Она также существенно снижает затраты памяти на вызов функции.
Массивы и курсоры
Если курсоры Transact-SQL должны проходить по данным, которые проще выразить в виде массива, управляемый код можно использовать с значительным повышением производительности.
Строковые данные
Данные символов SQL Server, такие как varchar, могут быть типа SqlString или SqlChars в управляемых функциях. Переменные типа SqlString создают в памяти экземпляр всего значения целиком. Переменные типа SqlChars обеспечивают потоковый интерфейс, который позволяет добиться более высокой производительности и масштабируемости, так как не создает в памяти экземпляра всего значения сразу. Это становится важным для данных больших объектов (LOB). Кроме того, с помощью потокового интерфейса, возвращаемого методом SqlXml.CreateReader()
, можно получить доступ к XML-данным на сервере.
CLR и расширенные хранимые процедуры
Microsoft.SqlServer.Server
Интерфейсы программирования приложений (API), позволяющие управляемым процедурам отправлять результирующие наборы клиенту лучше, чем 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. И наоборот, 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 килобайтов (КБ) помещается в кучу больших объектов, что приводит к снижению производительности сборки мусора, чем многие меньшие выделения. Например, если необходимо выделить большой многомерный массив, лучше выделить многомерный массив.