Размер строк и таблицы для таблиц, оптимизированных для памяти
Применяется к:SQL ServerAzure SQL DatabaseAzure, управляемому экземпляру SQL Azure
До SQL Server 2016 (13.x) размер данных в строке оптимизированной для памяти таблицы не может превышать 8 060 байт. Однако начиная с SQL Server 2016 (13.x) и в Базе данных SQL Azure теперь можно создать оптимизированную для памяти таблицу с несколькими большими столбцами (например, несколькими столбцами varbinary(8000) и бизнес-столбцами (т. е. varbinary(max), varchar(max) и nvarchar(max)) и выполнять операции с ними с помощью встроенных скомпилированных модулей T-SQL и типов таблиц.
Столбцы, превышающие максимальный размер строки в 8060 байт, размещаются вне строки в специальной внутренней таблице. У каждого такого столбца имеется соответствующая внутренняя таблица, которая, в свою очередь, имеет один некластеризованный индекс. Дополнительные сведения об этих внутренних таблицах, используемых для столбцов вне строк, см. в sys.memory_optimized_tables_internal_attributes (Transact-SQL).
Существуют определенные сценарии, в которых удобно вычислять размер строки и таблицы.
Какой объем памяти используется таблицей?
Объем используемой таблицей памяти невозможно подсчитать точно. На объем используемой памяти влияет множество факторов. Это такие факторы, как постраничное выделение места в памяти, размещение, кэширование и заполнение. Кроме того, несколько версий строк, которые имеют активные связанные транзакции либо ожидают сборку мусора.
Минимальный размер, необходимый для данных и индексов в таблице, определяется вычислением для [размера таблицы], о котором рассказывается ниже.
Вычисление используемой памяти в самом лучшем случае может быть выполнено лишь приближенно, поэтому рекомендуется включить планирование вместимости в планы разработки.
Каков размер строки данных, и укладывается ли он в ограничение размера строки 8060 байт? Чтобы получить ответ на эти вопросы, используйте вычисление для [размера текста строки], о котором рассказывается ниже.
Таблица, оптимизированная для памяти, представляет собой набор строк, а также индексов, которые содержат указатели на строки. На следующей схеме показана таблица с индексами и строками, которые в свою очередь содержат заголовки и текст:
Таблица, оптимизированная для памяти, состоящая из индексов и строк.
Размер таблицы вычислений
Размер, занимаемый таблицей в памяти (в байтах) вычисляется следующим образом.
[table size] = [size of index 1] + ... + [size of index n] + ([row size] * [row count])
Размер хэш-индекса фиксируется на момент создания таблицы и зависит от фактического числа контейнеров. Значение bucket_count
, указанное спецификацией индекса, округляется в сторону увеличения до ближайшей степени числа 2 для получения фактического числа контейнеров. Например, если заданное число bucket_count равно 100 000, то фактическое число контейнеров для индекса составляет 131 072.
[hash index size] = 8 * [actual bucket count]
Размер некластеризованного индекса определяется в [row count] * [index key size]
.
Размер строки вычисляется путем сложения значений для заголовка и текста:
[row size] = [row header size] + [actual row body size]
[row header size] = 24 + 8 * [number of indexes]
Размер текста строки вычислений
Структура строк. Строки в таблице, оптимизированной для памяти, включают следующие компоненты.
Заголовок строки содержит метку времени, необходимую для управления версиями строки. Заголовок строки также содержит указатель индекса, который позволяет реализовать цепочку строк в хэш-контейнере (описано выше).
Текст строки содержит фактические данные столбцов, которые включают некоторые вспомогательные сведения, такие как массив значений NULL для столбцов, допускающих значение NULL, и массив смещений для типов данных с переменной длиной.
На следующем рисунке показана структура строк для таблицы с двумя индексами.
Метки времени начала и конца показывают период, в котором определенная версия строки является допустимой. Транзакции, запускаемые в данном интервале, могут видеть эту версию строки. Дополнительные сведения см. в разделе Транзакции с таблицами, оптимизированными для памяти.
Указатели индекса указывают на следующую строку в цепочке, принадлежащей хэш-контейнеру. На следующем рисунке показана структура таблицы с двумя столбцами (имя, город) и двумя индексами, один для столбца name и второй для столбца city.
На этом рисунке имена Джон и Джейн хэшированы на первый контейнер. Сьюзан хэширована на втором контейнере. Города Пекин и Богота хэшированы на первом контейнере. Париж и Прага хэшированы на втором контейнере.
Таким образом, цепочки для хэш-индекса по именам выглядят следующим образом.
Первый контейнер: (Джон, Пекин); (Джон, Париж); (Джейн, Прага)
Второй контейнер: (Сьюзан, Богота)
Цепочки для индекса по городам выглядят следующим образом:
Первый контейнер: (Джон Пекин), (Сьюзан, Богота)
Второй контейнер: (Джон, Пекин); (Джон, Париж); (Джейн, Прага)
Конечная метка времени ∞ (бесконечность) указывает, что это действительная на данный момент версия строки. Строка была обновлена или удалена с того момента, как была записана эта версия.
Для времени больше 200 таблица содержит следующие строки.
Имя | City |
---|---|
Джон | Пекин |
Джейн | Prague |
Однако любая активная транзакция с начальным временем 100 увидит следующую версию таблицы.
Имя | City |
---|---|
Джон | Париж |
Джейн | Prague |
Сьюзан | Богота |
Вычисление [размера текста строки] демонстрируется в следующей таблице.
Размер текста строки вычисляется двумя способами: вычисляемый размер и фактический размер.
Вычисляемый размер (далее — вычисляемый размер строки) используется для того, чтобы определить, не превышает ли размер строки ограничение в 8060 байт.
Фактический размер (далее — фактический размер строки) представляет собой фактический размер строки в памяти и в файлах контрольных точек.
Оба показателя, вычисляемый размер строки и фактический размер строки, вычисляются схожим образом. Отличается только вычисление размера столбцов (n)varchar(I) и столбцов varbinary (I), как показано в нижней части таблицы. Вычисляемый размер строки использует в качестве размера столбца декларируемый размер i , тогда как фактический размер строки использует фактический размер данных.
В следующей таблице описано вычисление размера текста строки как фактический размер текста строки = SUM(размер мелких типов) + 2 + 2 * число столбцов глубокого типа.
Раздел | Размер | Комментарии |
---|---|---|
Столбцы поверхностных типов | SUM [размер поверхностных типов] Размер отдельных типов в байтах: Bit: 1 Tinyint: 1 Smallint: 2 Int: 4 Real: 4 Smalldatetime: 4 Smallmoney: 4 Bigint: 8 Datetime: 8 Datetime2: 8 Float: 8 Money: 8 Числовой (точность <=18): 8 Time: 8 Числовой (точность>18): 16 Uniqueidentifier: 16 |
|
Заполнение столбца поверхностного типа | Возможны следующие значения: 1, если в таблице присутствуют столбцы глубоких типов, а общий размер данных в столбцах поверхностного типа является нечетным числом. 0 в остальных случаях |
Глубокие типы — это типы (var)binary и (n)(var)char. |
Массив смещений для столбцов глубоких типов | Возможны следующие значения: 0, если в таблице нет столбцов глубоких типов 2 + 2 * [количество столбцов глубоких типов] во всех остальных случаях |
Глубокие типы — это типы (var)binary и (n)(var)char. |
Массив значений NULL | [количество столбцов, в которых допустимы значения NULL] / 8, с округлением в сторону увеличения до целого числа байт. | Массив содержит один бит для каждого столбца, допускающего значения NULL. Эта величина округляется в сторону увеличения до целого числа байт. |
Заполнение массива значений NULL | Возможны следующие значения: 1, если в таблице имеются столбцы глубоких типов данных и размер массива значений NULL равен нечетному числу байтов. 0 в остальных случаях |
Глубокие типы — это типы (var)binary и (n)(var)char. |
Заполнение | Если в таблице нет столбцов глубоких типов: 0 Если есть столбцы глубоких типов данных, добавляется 0–7 байт заполнения, исходя из наибольшего выравнивания, требующегося для столбцов поверхностных данных. Каждый столбец поверхностных типов требует выравнивания, равного его размеру (как показано в документе выше), за исключением столбцов GUID, которые требуют выравнивания на 1 байт (а не на 16), и числовых столбцов, которые всегда требуют выравнивания 8 байт (ни в коем случае не 16). Используется наибольшее требование выравнивания среди всех столбцов поверхностных типов, и заполнение 0–7 байт добавляется таким образом, чтобы общий размер на этот момент (без столбцов глубоких типов) был кратным числу необходимых выравниваний. |
Глубокие типы — это типы (var)binary и (n)(var)char. |
Столбцы глубоких типов фиксированной длины | SUM (размер столбцов глубоких типов фиксированной длины) Размер каждого столбца составляет: i для типов char(i) и binary(i). 2 * i для типа nchar(i) |
Столбцы глубоких типов данных фиксированной длины — это столбцы типов char(i), nchar(i) или binary(i). |
Столбцы глубоких типов данных переменной длины вычисляемый размер | SUM (вычисляемый размер столбцов глубоких типов данных переменной длины) вычисляемый размер каждого столбца составляет: i для типов varchar(i) и varbinary(i) 2 * i для типа nvarchar(i) |
Эта строка применяется только к вычисляемому размеру строки. Столбцы глубоких типов переменной длины — это столбцы типов varchar(i), nvarchar(i) или varbinary(i). вычисляемый размер определяется максимальной длиной (i) столбца. |
Столбцы глубоких типов данных переменной длины фактический размер | SUM (фактический размер столбцов глубоких типов данных переменной длины) Фактический размер каждого столбца составляет: n, где n — количество символов, хранящихся в столбце, для типа varchar(i). 2 * n, где n — количество символов, хранящихся в столбце, для типа nvarchar(i). n, где n — число байтов, хранящихся в столбце, для типа varbinary(i). |
Эта строка применяется только к фактическому размеру строки. Фактический размер определяется данными, которые хранятся в столбцах в данной строке. |
Пример: вычисление размера строки и таблицы
Для хэш-индекса фактическое число контейнеров округляется в сторону увеличения до ближайшей степени числа 2. Например, если заданное число bucket_count
равно 100 000, то фактическое число контейнеров для индекса составляет 131 072.
Рассмотрим таблицу Orders со следующим определением:
CREATE TABLE dbo.Orders (
OrderID int NOT NULL
PRIMARY KEY NONCLUSTERED,
CustomerID int NOT NULL
INDEX IX_CustomerID HASH WITH (BUCKET_COUNT=10000),
OrderDate datetime NOT NULL,
OrderDescription nvarchar(1000)
) WITH (MEMORY_OPTIMIZED=ON)
GO
Обратите внимание, что эта таблица содержит один хэш-индекс и некластеризованный индекс (первичный ключ). Кроме того, она содержит три столбца фиксированной длины и один столбец переменной длины, при этом один из столбцов допускает значения NULL (OrderDescription
). Допустим, таблица Orders
содержит 8379 строк, а средняя длина значений в столбце OrderDescription
составляет 78 символов.
Чтобы определить размер таблицы, сначала необходимо определить размер индексов. Для обоих индексов указан показатель bucket_count, равный 10 000. Эта величина округляется в сторону увеличения до ближайшей степени числа 2: 16 384. Поэтому общий размер индексов для таблицы Orders составляет:
8 * 16384 = 131072 bytes
Остается найти размер данных таблицы, который равен
[row size] * [row count] = [row size] * 8379
(Пример таблицы содержит 8379 строк.) Теперь у нас есть:
[row size] = [row header size] + [actual row body size]
[row header size] = 24 + 8 * [number of indices] = 24 + 8 * 1 = 32 bytes
Теперь давайте рассчитаем [фактический размер текста строки].
Столбцы поверхностных типов:
SUM([size of shallow types]) = 4 [int] + 4 [int] + 8 [datetime] = 16
Заполнение для столбцов поверхностных типов равно 0, поскольку общий размер столбцов поверхностного типа является четным числом.
Массив смещений для столбцов глубоких типов:
2 + 2 * [number of deep type columns] = 2 + 2 * 1 = 4
Массив значений NULL = 1
Заполнение массива значений NULL = 1, так как размер массива значений NULL является нечетным числом, а в таблице есть столбцы глубоких типов.
Заполнение
8 — наибольшее требования выравнивания.
Размер на данный момент равен 16 + 0 + 4 + 1 + 1 = 22.
Ближайшее число, кратное 8, — это 24.
В итоге заполнение составляет 24 – 22 = 2 байта.
В таблице нет столбцов глубоких типов переменной длины (столбцов глубоких типов фиксированной длины: 0).
Фактический размер столбца глубокого типа составляет 2 * 78 = 156. Единственный столбец глубокого типа
OrderDescription
имеет типnvarchar
.
[actual row body size] = 24 + 156 = 180 bytes
Для завершения вычисления:
[row size] = 32 + 180 = 212 bytes
[table size] = 8 * 16384 + 212 * 8379 = 131072 + 1776348 = 1907420
Таким образом, общий размер, занимаемый таблицей в памяти, составляет около 2 мегабайт. Это значение не учитывает потенциальные издержки при выделении памяти, а также управление версиями строк, необходимое для доступа транзакций к этой таблице.
Фактический размер памяти, выделяемый для данной таблицы и используемый ею и ее индексами, можно получить при помощи следующего запроса:
select * from sys.dm_db_xtp_table_memory_stats
where object_id = object_id('dbo.Orders')
Ограничения столбцов вне строки
Ниже перечислены некоторые ограничения и пояснения, касающиеся использования столбцов "вне строки" в таблице, оптимизированной для памяти.
- Если имеется индекс columnstore для таблицы, оптимизированной для памяти, то все столбцы должны умещаться "в строке".
- Но все ключевые столбцы индекса должны хранится "в строке". Если ключевой столбец индекса не помещается "в строке", добавление индекса завершается ошибкой.
- Пояснения по изменению таблицы, оптимизированной для памяти, со столбцами "вне строки".
- Для больших объектов (LOB) ограничение размера соответствует аналогичному ограничению для таблиц на диске (лимит 2 ГБ на значения LOB).
- Для обеспечения оптимальной производительности рекомендуется проследить, чтобы большинство столбцов умещалось в 8060 байт.
Некоторые из этих особенностей подробно рассмотрены в записи блога о новых возможностях выполняющейся в памяти OLTP в SQL Server 2016, появившихся после выпуска CTP3.
См. также
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по