Введение в таблицы, оптимизированные для памяти
Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure
Оптимизированные для памяти таблицы создаются с помощью CREATE TABLE (Transact-SQL).
Таблицы, оптимизированные для памяти, по умолчанию полностью устойчивы. Как и транзакции на (стандартных) дисковых таблицах, транзакции на оптимизированных для памяти таблицах полностью соответствуют классификации ACID (atomic, consistent, isolated, durable — атомарные, целостные, изолированные и устойчивые). Оптимизированные для памяти таблицы и скомпилированные в собственном коде хранимые процедуры поддерживают только подмножество функций Transact-SQL.
Начиная с SQL Server 2016 и в базе данных SQL Azure нет ограничений для параметров сортировки или кодовых страниц , относящихся к OLTP в памяти.
Первичное хранилище для таблиц, оптимизированных для памяти, — это основная память. Строки из таблицы считываются и записываются в память. Вторая копия табличных данных хранится на диске, но только с целью увеличения устойчивости. Дополнительные сведения о надежных таблицах см. в разделе Создание и управление хранилищем для оптимизированных для памяти объектов . Данные в таблицах, оптимизированных для памяти, считываются только с диска во время восстановления базы данных (например, после перезапуска сервера).
Чтобы еще больше повысить производительность, OLTP в памяти поддерживает устойчивые таблицы с отложенной устойчивостью транзакций. Отложенные устойчивые транзакции сохраняются на диск вскоре после фиксации транзакции и возврата управления клиенту. Платой за повышение производительности является то, что зафиксированные транзакции, не сохраненные на диск, теряются при сбое или отказе сервера.
Помимо таблиц, оптимизированных для устойчивой памяти по умолчанию, SQL Server также поддерживает несовременные оптимизированные для памяти таблицы, которые не регистрируются и их данные не сохраняются на диске. Это означает, что транзакции на этих таблицах не требуют каких-либо дисковых операций ввода-вывода, но их данные не будут восстановлены при сбое или отработке отказа сервера.
OLTP в памяти интегрирован с SQL Server, чтобы обеспечить простой интерфейс во всех областях, таких как разработка, развертывание, управляемость и поддержка. База данных может содержать как объекты в памяти, так и объекты на диске.
Строки в оптимизированных для памяти таблицах имеют версии. То есть каждая строка в таблице потенциально имеет несколько версий. Все версии строк сохраняются в одной структуре данных таблицы. Управление версиями строк используется, чтобы разрешить параллельный режим чтения и записи для одной строки. Дополнительные сведения о параллельном режиме чтения и записи для одной строки см. в разделе Операции с таблицами, оптимизированными для памяти.
На следующем рисунке показана работа с несколькими версиями строк. На схеме показана таблица с тремя строками, у каждой строки своя версия.
Таблица содержит три строки: r1, r2 и r3. r1 содержит три версии, r2 — 2 версии, и r3 — 4 версии. Обратите внимание, что разные версии одной и той же строки не обязательно занимают последовательные области памяти. Различные версии строк могут быть распределены по всей структуре данных таблицы.
Структуру данных таблицы, оптимизированной для памяти, можно рассматривать как коллекцию версий строк. Строки в таблицах, сохраняемых на диске, разбиты по страницам и расширениям, при этом доступ к отдельным строкам осуществляется через номер страницы и смещение. Доступ к версиям строк в таблицах с оптимизацией для памяти осуществляется посредством указателей памяти, занимающих 8 байт.
Доступ к данным в таблицах, оптимизированных для памяти, можно получить двумя способами:
Использование хранимых процедур, скомпилированных в собственном коде.
С помощью интерпретированного Transact-SQL вне скомпилированной в собственном коде хранимой процедуры. Эти инструкции Transact-SQL могут находиться в интерпретированных хранимых процедурах или могут быть нерегламентированными инструкциями Transact-SQL.
Доступ к данным в оптимизированных для памяти таблицах
Доступ к оптимизированным для памяти таблицам наиболее эффективным образом можно осуществлять из скомпилированных в собственном коде хранимых процедур (Скомпилированные в собственном коде хранимые процедуры). Кроме того, к таблицам, оптимизированным для памяти, можно получить доступ с помощью (традиционного) интерпретированного Transact-SQL. Интерпретированный Transact-SQL относится к доступу к оптимизированным для памяти таблицам без скомпилированной хранимой процедуры в собственном коде. Некоторые примеры интерпретированного доступа Transact-SQL включают доступ к таблице, оптимизированной для памяти, из триггера DML, нерегламентированного пакета Transact-SQL, представления и табличного значения функции.
В следующей таблице приведены сведения о собственном и интерпретируемом доступе Transact-SQL для различных объектов.
Функция | Доступ с помощью хранимой процедуры, скомпилированной в собственном коде | Интерпретируемый доступ Transact-SQL | Доступ по CLR-адресу |
---|---|---|---|
Таблица, оптимизированная для памяти | Да | Да | Нет* |
Табличный тип, оптимизированный для памяти | Да | Да | Нет |
Хранимая процедура, скомпилированная в собственном коде | Вложение скомпилированных в собственном коде хранимых процедур поддерживается. Синтаксис EXECUTE можно использовать внутри хранимых процедур при условии, что соответствующие процедуры также скомпилированы в собственном коде. | Да | Нет* |
*Невозможно получить доступ к оптимизированной для памяти таблице или скомпилированной в собственном коде хранимой процедуре из контекстного подключения (подключение из SQL Server при выполнении модуля CLR). Однако можно создать и открыть другое соединение, из которого можно получить доступ к оптимизированным для памяти таблицам и хранимым процедурам, скомпилированным в собственном коде.
Производительность и масштабируемость
Следующие факторы влияют на повышение производительности при использовании OLTP в памяти:
Взаимодействие. Выигрыш в производительности приложения с множеством вызовов коротких хранимых процедур может быть меньше, чем у приложения с меньшим числом вызовов и более функциональными хранимыми процедурами.
Выполнение Transact-SQL. В памяти OLTP обеспечивает оптимальную производительность при использовании скомпилированных в собственном коде хранимых процедур, а не интерпретированных хранимых процедур или выполнения запросов. Иногда удобно получать доступ к оптимизированным для памяти таблицам из таких хранимых процедур.
Просмотр диапазона или поиск точек. Некластеризованные оптимизированные для памяти индексы поддерживают просмотр диапазона и упорядоченные просмотры. С уточняющими запросами оптимизированные для памяти хэш-индексы более производительны, чем оптимизированные для памяти некластеризованные индексы. Оптимизированные для памяти некластеризованные индексы имеют более высокую производительность, чем дисковые индексы.
- Начиная с версии SQL Server 2016 план запроса оптимизированной для памяти таблицы может сканировать таблицу в параллельном режиме. Это повышает производительность аналитических запросов.
- Хэш-индексы также стали поддерживать сканирование в параллельном режиме в SQL Server 2016.
- Некластеризованные индексы также стали поддерживать сканирование в параллельном режиме в SQL Server 2016.
- Индексы columnstore поддерживают сканирование в параллельном режиме с момента своего появления в SQL Server 2014.
Операции с индексами. Операции с индексами не регистрируются и находятся только в памяти.
Параллелизм. Производительность приложений, которая зависит от параллелизма компонента уровня СУБД, например от конфликтов кратковременной блокировки, значительно повышается при переходе на выполняющуюся в памяти OLTP.
В следующей таблице перечислены проблемы с производительностью и масштабируемостью, которые часто встречаются в реляционных базах данных, и описывается, как OLTP в памяти может улучшить производительность.
Проблема | Влияние OLTP в памяти |
---|---|
Производительность Высокая интенсивность использования ресурсов (ЦП, ввода-вывода, сети или памяти). |
ЦП Скомпилированные хранимые процедуры в собственном коде могут значительно снизить использование ЦП, так как они требуют значительно меньше инструкций для выполнения инструкции Transact-SQL по сравнению с интерпретируемыми хранимыми процедурами. In-Memory OLTP может снизить затраты на оборудование для масштабированных рабочих нагрузок, поскольку один сервер потенциально может обеспечить пропускную способность 5–10 серверов. ВВОД-ВЫВОД OLTP в памяти может уменьшить влияние узких мест в операциях ввода-вывода при обработке страниц данных или индекса. Кроме того, назначение контрольных точек для объектов OLTP в памяти происходит непрерывно и не приводит к неожиданному увеличению количества операций ввода-вывода. Однако если рабочее множество важных для производительности таблиц не помещается в памяти, то OLTP в памяти не улучшит производительность, поскольку данные должны быть резидентными. Если возникает задержка в операциях ввода-вывода при ведении журнала, то OLTP в памяти может снизить эту задержку, так как в журнал записывается меньше данных. Если одна или несколько таблиц, оптимизированных для памяти, настроены как устойчивые, журналирование данных можно исключить. Память OLTP в памяти не повышает производительность. OLTP в памяти может вызывать дополнительную нагрузку на память, так как объекты должны быть резидентными. Network OLTP в памяти не повышает производительность. Данные нужно передавать с уровня данных на уровень приложения. |
Масштабируемость Большинство проблем масштабирования в приложениях SQL Server вызваны проблемами параллелизма, такими как конфликт в блокировках, блокировках и спин-блокировках. |
Конфликты кратковременных блокировок Типичный сценарий — конфликт на последней странице индекса при параллельной вставке строк в порядке значений ключей. OLTP в памяти не использует кратковременные блокировки при доступе к данным, поэтому проблемы масштабируемости, связанные с конфликтом за кратковременные блокировки, полностью устраняются. Конфликт спин-блокировок OLTP в памяти не использует кратковременные блокировки при доступе к данным, поэтому проблемы масштабируемости, связанные с состязанием за спин-блокировки, полностью устраняются. Конфликты, связанные с блокировкой OLTP в памяти устраняет критические препятствия между операциями чтения и записи в приложении базы данных, поскольку используется новая форма управления оптимистической конкуренцией для реализации всех уровней изоляции транзакций. OLTP в памяти не использует базу данных TempDB для хранения версий строк. Если ошибка масштабирования вызвана конфликтом между двумя операциями записи, например двумя параллельными транзакциями, которые пытаются обновить одну и ту же строку, OLTP в памяти позволяет завершить одну транзакцию и отклоняет другую. Поврежденную транзакцию необходимо представить повторно явно или неявно. В любом случае необходимо внести изменения в приложение. Если в приложении часто возникают конфликты между двумя операциями записи, значимость оптимистической блокировки уменьшается. Приложение не подходит для работы с OLTP в памяти. В большинстве OLTP-приложений отсутствуют конфликты записи, если конфликт не вызывается укрупнением блокировки. |
Безопасность на уровне строк в оптимизированных для памяти таблицах
Безопасность на уровне строк поддерживается в таблицах, оптимизированных для памяти. Применение политик безопасности на уровне строк в таблицах, оптимизированных для памяти, практически не отличается от применения политик в таблицах на дисках, за исключением того, что встроенные функции с табличным значением, используемые в качестве предикатов безопасности, должны быть скомпилированы в собственном коде (созданы с помощью параметра WITH NATIVE_COMPILATION). Подробные сведения см. в подразделе Совместимость с разными компонентами раздела Безопасность на уровне строк .
В таблицы в памяти включены различные встроенные функции безопасности, необходимые для безопасности на уровне строк. Подробные сведения см. в разделе Встроенные функции в модулях, скомпилированных в собственном коде.
EXECUTE AS CALLER . Все собственные модули теперь поддерживают и используют EXECUTE AS CALLER по умолчанию, даже если указание не задано. Это происходит потому, что предполагается, что все функции предиката безопасности на уровне строк будут использовать предложение EXECUTE AS CALLER, чтобы функция (и все встроенные функции, используемые в ней) вычислялась в контексте вызывающего пользователя.
Производительность предложения EXECUTE AS CALLER немного снижена (приблизительно на 10 %) из-за проверок разрешений вызывающего объекта. Если модуль явно указывает предложение EXECUTE AS OWNER или EXECUTE AS SELF, это позволит избежать проверок разрешений и сопутствующего снижения производительности. Однако использование любого из этих параметров вместе с встроенными функциями, указанными выше, повлечет за собой значительное снижение производительности из-за необходимости переключения контекста.
Сценарии
Краткое обсуждение типичных сценариев, в которых OLTP в памяти может повысить производительность, см. в разделе OLTP в памяти.