Пример базы данных для выполняющейся в памяти OLTPSample Database for In-Memory OLTP

Применимо к:Applies to: даSQL ServerSQL Server (все поддерживаемые версии) yesSQL ServerSQL Server (all supported versions) ДаБаза данных SQL AzureAzure SQL DatabaseYesБаза данных SQL AzureAzure SQL DatabaseПрименимо к:Applies to: даSQL ServerSQL Server (все поддерживаемые версии) yesSQL ServerSQL Server (all supported versions) ДаБаза данных SQL AzureAzure SQL DatabaseYesБаза данных SQL AzureAzure SQL Database

ОбзорOverview

Этот пример демонстрирует возможности выполняющейся в памяти OLTP.This sample showcases the In-Memory OLTP feature. Он показывает оптимизированные для памяти таблицы и скомпилированные в собственном коде хранимые процедуры. С его помощью можно также продемонстрировать преимущества выполняющейся в памяти OLTP.It shows memory-optimized tables and natively compiled stored procedures, and can be used to demonstrate performance benefits of In-Memory OLTP.

Примечание

Этот раздел о SQL Server 2014 (12.x)SQL Server 2014 (12.x)можно найти в статье Расширения AdventureWorks для демонстрации выполняющейся в памяти OLTP.To view this topic for SQL Server 2014 (12.x)SQL Server 2014 (12.x), see Extensions to AdventureWorks to Demonstrate In-Memory OLTP.

Пример выполняет преобразование 5 таблиц в базе данных AdventureWorks в оптимизированные для памяти таблицы. В нем также есть демонстрационная рабочая нагрузка в форме обработки заказа на продажу.The sample migrates five tables in the AdventureWorks database to memory-optimized, and it includes a demo workload for sales order processing. С помощью этой демонстрационной рабочей нагрузки можно оценить выигрыш по производительности, который формируется при использовании выполняющейся в памяти OLTP на сервере.You can use this demo workload to see the performance benefit of using In-Memory OLTP on your server.

В описании примера рассматриваются компромиссные решения, реализованные при переносе таблиц в выполняющуюся в памяти OLTP с указанием тех функций, которые (пока еще) не поддерживаются для оптимизированных для памяти таблиц.In the description of the sample, we discuss the tradeoffs that were made in migrating the tables to In-Memory OLTP to account for the features that are not (yet) supported for memory-optimized tables.

Документация по этому примеру имеет следующую структуру.The documentation of this sample is structured as follows:

Предварительные требованияPrerequisites

Установка образца OLTP в памяти на основе AdventureWorksInstalling the In-Memory OLTP sample based on AdventureWorks

Чтобы установить образец, выполните следующие действия.Follow these steps to install the sample:

  1. Скачайте файлы AdventureWorks2016CTP3.bak и SQLServer2016CTP3Samples.zip со страницы по адресу https://github.com/microsoft/sql-server-samples/releases/tag/adventureworks в папку на компьютере, например c:\temp.Download AdventureWorks2016CTP3.bak and SQLServer2016CTP3Samples.zip from: https://github.com/microsoft/sql-server-samples/releases/tag/adventureworks to a local folder, for example 'c:\temp'.

  2. Восстановите резервную копию базы данных с помощью Transact-SQLTransact-SQL или в среде SQL Server Management StudioSQL Server Management Studio.Restore the database backup using Transact-SQLTransact-SQL or SQL Server Management StudioSQL Server Management Studio:

    1. Задайте целевую папку и имя для файла данных, напримерIdentify the target folder and filename for the data file, for example

      h:\DATA\AdventureWorks2016CTP3_Data.mdf'h:\DATA\AdventureWorks2016CTP3_Data.mdf'

    2. Задайте целевую папку и имя для файла журнала, напримерIdentify the target folder and filename for the log file, for example

      i:\DATA\AdventureWorks2016CTP3_log.ldf'i:\DATA\AdventureWorks2016CTP3_log.ldf'

      1. Файл журнала следует разместить на диске, отличном от того, на котором находится файл данных. В идеале для обеспечения максимальной производительности это должен быть высокоскоростной диск, например хранилище SSD или PCI.The log file should be placed on a different drive than the data file, ideally a low latency drive such as an SSD or PCIe storage, for maximum performance.

    Пример скрипта T-SQL:Example T-SQL script:

    RESTORE DATABASE [AdventureWorks2016CTP3]   
      FROM DISK = N'C:\temp\AdventureWorks2016CTP3.bak'   
        WITH FILE = 1,    
      MOVE N'AdventureWorks2016_Data' TO N'h:\DATA\AdventureWorks2016CTP3_Data.mdf',    
      MOVE N'AdventureWorks2016_Log' TO N'i:\DATA\AdventureWorks2016CTP3_log.ldf',  
      MOVE N'AdventureWorks2016CTP3_mod' TO N'h:\data\AdventureWorks2016CTP3_mod'  
     GO  
    
  3. Чтобы просмотреть примеры скриптов и рабочей нагрузки, распакуйте файл SQLServer2016CTP3Samples.zip в папку на компьютере.To view the sample scripts and workload, unpack the file SQLServer2016CTP3Samples.zip to a local folder. Инструкции по запуску рабочей нагрузки см. в файле In-Memory OLTP\readme.txt.Consult the file In-Memory OLTP\readme.txt for instructions on running the workload.

Описание образцов таблиц и процедурDescription of the sample tables and procedures

Образец создает новые таблицы для продуктов и заказов на продажу на основе существующих в базе данных AdventureWorks таблиц.The sample creates new tables for products and sales orders, based on existing tables in AdventureWorks. Схема новых таблиц похожа на схему существующих таблиц, а несколько различий в схемах описаны далее.The schema of the new tables is similar to the existing tables, with a few differences, as explained below.

Новые оптимизированные для памяти таблицы имеют суффикс "_inmem".The new memory-optimized tables carry the suffix '_inmem'. В образце также есть соответствующие таблицы с суффиксом "_ondisk" — эти таблицы можно использовать для сравнения "один к одному" между производительностью оптимизированных для памяти таблиц и таблиц на диске в системе.The sample also includes corresponding tables carrying the suffix '_ondisk' - these tables can be used to make a one-to-one comparison between the performance of memory-optimized tables and disk-based tables on your system..

Оптимизированные для памяти таблицы, используемые в рабочей нагрузке для сравнения производительности, являются полностью устойчивыми и работают с полным протоколированием.The memory-optimized tables used in the workload for performance comparison are fully durable and fully logged. Для повышения производительности они не жертвуют устойчивостью или надежностью.They do not sacrifice durability or reliability to attain the performance gain.

Целевой рабочей нагрузкой для этого образца является обработка заказа на продажу, в рамках которой также учитывается информация о продукте и скидки.The target workload for this sample is sales order processing, where we consider also information about products and discounts. Для этого используются таблицы SalesOrderHeader, SalesOrderDetail, Product, SpecialOffer и SpecialOfferProduct.To this end, the table SalesOrderHeader, SalesOrderDetail, Product, SpecialOffer, and SpecialOfferProduct.

Две новые хранимые процедуры, Sales.usp_InsertSalesOrder_inmem и Sales.usp_UpdateSalesOrderShipInfo_inmem, используются для вставки заказов на продажу и обновления сведений о доставке по данному заказу на продажу.Two new stored procedures, Sales.usp_InsertSalesOrder_inmem and Sales.usp_UpdateSalesOrderShipInfo_inmem, are used to insert sales orders and to update the shipping information of a given sales order.

Новая схема «Demo» содержит вспомогательные таблицы и хранимые процедуры для выполнения демонстрационной рабочей нагрузки.The new schema 'Demo' contains helper tables and stored procedures to execute a demo workload.

В частности, пример выполняющейся в памяти OLTP добавляет в базу данных AdventureWorks следующие объекты:Concretely, the In-Memory OLTP sample adds the following objects to AdventureWorks:

Таблицы, добавляемые образцомTables added by the sample

Новые таблицыThe New Tables

Sales.SalesOrderHeader_inmemSales.SalesOrderHeader_inmem

  • Данные заголовка о заказах на продажу.Header information about sales orders. Для каждого заказа на продажу в этой таблице есть отдельная строка.Each sales order has one row in this table.

Sales.SalesOrderDetail_inmemSales.SalesOrderDetail_inmem

  • Подробные сведения заказов на продажу.Details of sales orders. Для каждого элемента заказа на продажу в этой таблице есть отдельная строка.Each line item of a sales order has one row in this table.

Sales.SpecialOffer_inmemSales.SpecialOffer_inmem

  • Сведения о специальных предложениях, включая процент скидки, связанный с каждым специальным предложением.Information about special offers, including the discount percentage associated with each special offer.

Sales.SpecialOfferProduct_inmemSales.SpecialOfferProduct_inmem

  • Ссылочная таблица между специальными предложениями и продуктами.Reference table between special offers and products. Каждое специальное предложение может включать от нуля и более продуктов, а каждый продукт может содержать нуль и более специальных предложений.Each special offer can feature zero or more products, and each product can be featured in zero or more special offers.

Production.Product_inmemProduction.Product_inmem

  • Сведения о продуктах, включая их цену по прейскуранту.Information about products, including their list price.

Demo.DemoSalesOrderDetailSeedDemo.DemoSalesOrderDetailSeed

  • В этой демонстрационной рабочей нагрузке используется для формирования образцов заказов на продажу.Used in the demo workload to construct sample sales orders.

Те же таблицы, но находящиеся на диске:Disk-based variations of the tables:

  • Sales.SalesOrderHeader_ondiskSales.SalesOrderHeader_ondisk

  • Sales.SalesOrderDetail_ondiskSales.SalesOrderDetail_ondisk

  • Sales.SpecialOffer_ondiskSales.SpecialOffer_ondisk

  • Sales.SpecialOfferProduct_ondiskSales.SpecialOfferProduct_ondisk

  • Production.Product_ondiskProduction.Product_ondisk

Различия между исходными таблицами, находящимися на диске, и новыми, оптимизированными для памяти таблицамиDifferences between original disk-based and the and new memory-optimized tables

По большей части новые таблицы, представленные в данном образце, состоят из тех же столбцов и используют те же типы данных, что и исходные таблицы.For the most part, the new tables introduced by this sample use the same columns and the same data types as the original tables. Однако между ними есть несколько различий.However, there are a few differences. Далее приведены эти различия и обоснование внесенных изменений.We list the differences below, along with a rationale for the changes.

Sales.SalesOrderHeader_inmemSales.SalesOrderHeader_inmem

  • Ограничения по умолчанию поддерживаются для оптимизированных для памяти таблиц, и большинство ограничений по умолчанию переносятся как есть.Default constraints are supported for memory-optimized tables, and most default constraints we migrated as is. Однако исходная таблица Sales.SalesOrderHeader содержит два ограничения по умолчанию, которые получают текущую дату, для столбцов OrderDate и ModifiedDate.However, the original table Sales.SalesOrderHeader contains two default constraints that retrieve the current date, for the columns OrderDate and ModifiedDate. В рабочей нагрузке по обработке заказов значительного объема, когда множество заказов обрабатываются одновременно, наличие любого глобального ресурса может вызвать конфликт.In a high throughput order processing workload with much concurrency, any global resource can become a point of contention. Системное время является таким глобальным ресурсом, и мы заметили, что при выполнении рабочей нагрузки выполняющейся в памяти OLTP, вставляющей заказы на продажу, это может оказаться узким местом, в частности, если требуется получить системное время для нескольких столбцов из заголовка заказа на продажу, а также для подробных сведений о заказе на продажу.System time is such a global resource, and we have observed that it can become a bottleneck when running an In-Memory OLTP workload that inserts sales orders, in particular if the system time needs to be retrieved for multiple columns in the sales order header, as well as the sales order details. Для устранения этой проблемы в этом образце для каждого вставляемого заказа на продажу получение системного времени производится только один раз, после чего это значение используется для столбцов даты и времени в таблицах SalesOrderHeader_inmem и SalesOrderDetail_inmem, в хранимой процедуре Sales.usp_InsertSalesOrder_inmem.The problem is addressed in this sample by retrieving the system time only once for each sales order that is inserted, and use that value for the datetime columns in SalesOrderHeader_inmem and SalesOrderDetail_inmem, in the stored procedure Sales.usp_InsertSalesOrder_inmem.

  • Определяемые пользователем типы псевдонимов (UDT) . В исходной таблице используются два псевдонима UDT, dbo.OrderNumber и dbo.AccountNumber, для столбцов PurchaseOrderNumber и AccountNumber соответственно.Alias user-defined data types (UDTs) - The original table uses two alias UDTs dbo.OrderNumber and dbo.AccountNumber, for the columns PurchaseOrderNumber and AccountNumber, respectively. SQL Server 2016 (13.x);SQL Server 2016 (13.x) не поддерживает определяемые пользователем типы псевдонимов для оптимизированных для памяти таблиц, поэтому в новых таблицах используются системные типы данных nvarchar(25) и nvarchar(15) соответственно.does not support alias UDT for memory-optimized tables, thus the new tables use system data types nvarchar(25) and nvarchar(15), respectively.

  • Столбцы, допускающие значение NULL, в ключах индексов . В столбце SalesPersonID исходной таблицы могут содержаться значения NULL, а в столбцах новых таблиц значения NULL недопустимы. Кроме того, они имеют ограничение по умолчанию со значением (-1).Nullable columns in index keys - In the original table, the column SalesPersonID is nullable, while in the new tables the column is not nullable and has a default constraint with value (-1). Связано это с тем, что индексы в оптимизированных для памяти таблицах не могут содержать в ключе индекса столбцы, допускающие значение NULL; в этом случае значение –1 является заменой значения NULL.This circumstance is because indexes on memory-optimized tables cannot have nullable columns in the index key; -1 is a surrogate for NULL in this case.

  • Вычисляемые столбцыSQL Server 2016 (13.x);SQL Server 2016 (13.x). Вычисляемые столбцы SalesOrderNumber и TotalDue пропускаются, так как не поддерживает вычисляемые столбцы в оптимизированных для памяти таблицах.Computed columns - The computed columns SalesOrderNumber and TotalDue are omitted, as SQL Server 2016 (13.x);SQL Server 2016 (13.x) does not support computed columns in memory-optimized tables. Новое представление Sales.vSalesOrderHeader_extended_inmem отражает столбцы SalesOrderNumber и TotalDue.The new view Sales.vSalesOrderHeader_extended_inmem reflects the columns SalesOrderNumber and TotalDue. Поэтому при необходимости в этих столбцах можно использовать это представление.Therefore, you can use this view if these columns are needed.

    • Применимо к: SQL Server 2017 (14.x);SQL Server 2017 (14.x) CTP 1.1.Applies to: SQL Server 2017 (14.x);SQL Server 2017 (14.x) CTP 1.1.
      Начиная с версии SQL Server 2017 (14.x);SQL Server 2017 (14.x) CTP 1.1 вычисляемые столбцы поддерживаются в оптимизированных для памяти таблицах и индексах.Beginning with SQL Server 2017 (14.x);SQL Server 2017 (14.x) CTP 1.1, computed columns are supported in memory-optimized tables and indexes.
  • Ограничения внешнего ключа поддерживаются для оптимизированных для памяти таблиц в SQL Server 2016 (13.x);SQL Server 2016 (13.x), но только если связанные таблицы также оптимизированы для памяти.Foreign key constraints are supported for memory-optimized tables in SQL Server 2016 (13.x);SQL Server 2016 (13.x), but only if the referenced tables are also memory-optimized. Внешние ключи, ссылающиеся на таблицы, которые также переносятся в оптимизированные для памяти таблицы, сохраняются в перенесенных таблицах, а остальные внешние ключи пропускаются.Foreign keys that reference tables that are also migrated to memory-optimized are kept in the migrated tables, while other foreign keys are omitted. Кроме того, в образце рабочей нагрузки SalesOrderHeader_inmem является горячей таблицей, а ограничения внешнего ключа требуют дополнительной обработки для всех операций DML, поскольку при этом необходимо выполнять поиск и подстановку во всех остальных таблицах, на которые ссылаются эти ограничения.In addition, SalesOrderHeader_inmem is a hot table in the example workload, and foreign keys constraints require additional processing for all DML operations, as it requires lookups in all the other tables referenced in these constraints. Поэтому предполагается, что приложение обеспечивает для таблицы Sales.SalesOrderHeader_inmem ссылочную целостность, которая не проверяется при вставке строк.Therefore, the assumption is that the app ensures referential integrity for the Sales.SalesOrderHeader_inmem table, and referential integrity is not validated when rows are inserted.

  • Rowguid . Столбец rowguid опускается.Rowguid - The rowguid column is omitted. Притом что uniqueidentifier поддерживается для оптимизированных для памяти таблиц, параметр ROWGUIDCOL в SQL Server 2016 (13.x);SQL Server 2016 (13.x)для них не поддерживается.While uniqueidentifier is support for memory-optimized tables, the option ROWGUIDCOL is not supported in SQL Server 2016 (13.x);SQL Server 2016 (13.x). Столбцы этого вида обычно используются либо для репликации слиянием, либо для таблиц, в которых есть столбцы filestream.Columns of this kind are typically used for either merge replication or tables that have filestream columns. В этом образце нет ни того ни другого.This sample includes neither.

Sales.SalesOrderDetailSales.SalesOrderDetail

  • Ограничения по умолчанию. Как и в случае с SalesOrderHeader, ограничение по умолчанию, которому требуется системные дата и время, не переносится. Вместо этого хранимая процедура, вставляющая заказы на продажу, задает системные дату и время при первой вставке.Default constraints - similar to SalesOrderHeader, the default constraint requiring the system date/time is not migrated, instead the stored procedure inserting sales orders takes care of inserting the current system date/time on first insert.

  • Вычисляемые столбцы. Вычисляемый столбец LineTotal пропускается, так как в SQL Server 2016 (13.x);SQL Server 2016 (13.x) наличие вычисляемых столбцов в оптимизированных для памяти таблицах не поддерживается.Computed columns - the computed column LineTotal was not migrated as computed columns are not supported with memory-optimized tables in SQL Server 2016 (13.x);SQL Server 2016 (13.x). Для доступа к этому столбцу используйте представление Sales.vSalesOrderDetail_extended_inmem.To access this column, use the view Sales.vSalesOrderDetail_extended_inmem.

  • Rowguid . Столбец rowguid опускается.Rowguid - The rowguid column is omitted. Дополнительные сведения см. в описании таблицы SalesOrderHeader.For details see the description for the table SalesOrderHeader.

Production.ProductProduction.Product

  • Псевдонимы UDT. В исходной таблице используется определяемый пользователем тип данных dbo.Flag, который эквивалентен системному типу данных bit.Alias UDTs - the original table uses the user-defined data type dbo.Flag, which is equivalent to the system data type bit. В перенесенной таблице вместо него используется тип данных bit.The migrated table uses the bit data type instead.

  • Rowguid . Столбец rowguid опускается.Rowguid - The rowguid column is omitted. Дополнительные сведения см. в описании таблицы SalesOrderHeader.For details see the description for the table SalesOrderHeader.

Sales.SpecialOfferSales.SpecialOffer

  • Rowguid . Столбец rowguid опускается.Rowguid - The rowguid column is omitted. Дополнительные сведения см. в описании таблицы SalesOrderHeader.For details see the description for the table SalesOrderHeader.

Sales.SpecialOfferProductSales.SpecialOfferProduct

  • Rowguid . Столбец rowguid опускается.Rowguid - The rowguid column is omitted. Дополнительные сведения см. в описании таблицы SalesOrderHeader.For details see the description for the table SalesOrderHeader.

Соображения в отношении индексов в оптимизированных для памяти таблицахConsiderations for indexes on memory-optimized tables

Базовым индексом для оптимизированных для памяти таблиц является индекс NONCLUSTERED, который поддерживает уточняющие запросы (поиск по индексу с использованием предиката равенства), полный просмотр индекса и упорядоченный просмотр.The baseline index for memory-optimized tables is the NONCLUSTERED index, which supports point lookups (index seek on equality predicate), range scans (index seek in inequality predicate), full index scans, and ordered scans. Кроме того, индексы NONCLUSTERED поддерживают поиск в начальных столбцах ключа индекса.In addition, NONCLUSTERED indexes support searching on leading columns of the index key. По сути дела, индексы NONCLUSTERED оптимизированных для памяти таблиц поддерживают все операции, которые поддерживаются индексами NONCLUSTERED таблиц, находящихся на диске. Единственным исключением является обратный просмотр.In fact memory-optimized NONCLUSTERED indexes support all the operations supported by disk-based NONCLUSTERED indexes, with the only exception being backward scans. Поэтому использование индексов NONCLUSTERED в нашем случае является безопасным вариантом.Therefore, using NONCLUSTERED indexes is a safe choice for your indexes.

Для дальнейшей оптимизации рабочей нагрузки можно использовать индексы HASH.HASH indexes are can be used to further optimize the workload. Они особенно хорошо подходят для уточняющих запросов и вставки строк.They are particularly optimized for point lookups and row inserts. Однако следует учитывать, что они не поддерживают просмотр диапазонов, упорядоченный просмотр или поиск в начальных столбцах ключа индекса.However, one must consider that they do not support range scans, ordered scans, or search on leading index key columns. Поэтому при использовании этих индексов требуется соблюдать осторожность.Therefore, care needs to be taken when using these indexes. Кроме того, при создании необходимо указать параметр bucket_count.In addition, it is necessary to specify the bucket_count at create time. Обычно его значение должно быть в 1–2 раза больше числа значение ключей индекса, однако переоценка редко создает проблему.It should usually be set at between one and two times the number of index key values, but overestimating is usually not a problem.

Дополнительные указания по работе с индексами, а также указания по выбору правильного значения bucket_count см. в электронной документации.For more information, see Books Online for more details about index guidelines and guidelines for choosing the right bucket_count.

В электронной документации содержатся дополнительные сведения о следующих разделах:The Books Online provide more information about the following topics:

Индексы в перенесенных таблицах настроены для выполнения демонстрационной рабочей нагрузки по обработке заказов на продажу.The indexes on the migrated tables have been tuned for the demo sales order processing workload. Рабочая нагрузка состоит из операций вставки и уточняющих запросов, которые выполняются в таблицах Sales.SalesOrderHeader_inmem и Sales.SalesOrderDetail_inmem, а также операций уточняющих запросов, которые выполняются в столбцах первичного ключа из таблиц Production.Product_inmem и Sales.SpecialOffer_inmem.The workload relies on inserts and point lookups in the tables Sales.SalesOrderHeader_inmem and Sales.SalesOrderDetail_inmem, and it also relies on point lookups on the primary key columns in the tables Production.Product_inmem and Sales.SpecialOffer_inmem.

В таблице Sales.SalesOrderHeader_inmem есть три индекса, причем для обеспечения высокой производительности все они являются индексами HASH, а также потому, что для этой рабочей нагрузки не требуется упорядоченных просмотров или просмотров диапазона.Sales.SalesOrderHeader_inmem has three indexes, which are all HASH indexes for performance reasons, and because no ordered or range scans are needed for the workload.

  • Индекс HASH в (SalesOrderID): bucket_count задан в размере 10 миллионов (с округлением до 16 миллионов), поскольку ожидаемое количество заказов на продажу составляет 10 миллионов.HASH index on (SalesOrderID): bucket_count is sized at 10 million (rounded up to 16 million), because the expected number of sales orders is 10 million

  • Индекс HASH в (SalesPersonID): bucket_count равен одному миллиону.HASH index on (SalesPersonID): bucket_count is 1 million. Указанный набор данных не содержит много продавцов.The data set provided does not have many sales persons. Но большое значение bucket_count допускает будущее увеличение.But this large bucket_count allows for future growth. Кроме того, вы не оплачиваете снижение производительности при поиске по точкам, если размер значения bucket_count слишком велик.Plus you don't pay a performance penalty for point lookups if the bucket_count is oversized.

  • Индекс HASH в (CustomerID): bucket_count равен одному миллиону.HASH index on (CustomerID): bucket_count is 1 million. В предоставленном наборе данных нет большого числа клиентов, однако это дает место для расширения в будущем.The data set provided does not have a lot of customers, but this allows for future growth.

В таблице Sales.SalesOrderDetail_inmem есть три индекса, причем для обеспечения высокой производительности все они являются индексами HASH, а также потому, что для этой рабочей нагрузки не требуется упорядоченных просмотров или просмотров диапазона.Sales.SalesOrderDetail_inmem has three indexes, which are all HASH indexes for performance reasons, and because no ordered or range scans are needed for the workload.

  • Индекс HASH в (SalesOrderID, SalesOrderDetailID): это индекс первичного ключа; хотя уточняющие запросы в (SalesOrderID, SalesOrderDetailID) будут выполняться нечасто, использование индекса HASH для ключа позволяет ускорить вставку строк.HASH index on (SalesOrderID, SalesOrderDetailID): this is the primary key index, and even though lookups on (SalesOrderID, SalesOrderDetailID) will be infrequent, using a hash index for the key speeds up row inserts. Параметр bucket_count задан в размере 50 миллионов (с округлением до 67 миллионов): ожидаемое количество заказов на продажу составляет 10 миллионов, а значение параметра выбрано с тем расчетом, что каждый заказ будет содержать пять элементовThe bucket_count is sized at 50 million (rounded up to 67 million): the expected number of sales orders is 10 million, and this is sized to have an average of five items per order

  • Индекс HASH в (SalesOrderID): уточняющие запросы заказов на продажу выполняются часто: необходимо будет находить все линейные элементы, соответствующие одному заказу.HASH index on (SalesOrderID): lookups by sales order are frequent: you will want to find all the line items corresponding to a single order. bucket_count задан в размере 10 миллионов (с округлением до 16 миллионов), поскольку ожидаемое количество заказов на продажу составляет 10 миллионов.bucket_count is sized at 10 million (rounded up to 16 million), because the expected number of sales orders is 10 million

  • Индекс HASH в (ProductID): bucket_count равен одному миллиону.HASH index on (ProductID): bucket_count is 1 million. В предоставленном наборе данных нет большого числа продуктов, однако это дает место для расширения в будущем.The data set provided does not have a lot of product, but this allows for future growth.

В таблице Production.Product_inmem есть три индексаProduction.Product_inmem has three indexes

  • Индекс HASH в (ProductID): запросы по ProductID выполняются по критическому пути этой демонстрационной рабочей нагрузки, поэтому здесь применяется индекс HASHHASH index on (ProductID): lookups on ProductID are in the critical path for the demo workload, therefore this is a hash index

  • Индекс NONCLUSTERED в (Name): это позволит выполнять упорядоченные просмотры названий продуктовNONCLUSTERED index on (Name): this will allow ordered scans of product names

  • Индекс NONCLUSTERED в (ProductNumber): это позволит выполнять упорядоченные просмотры количества продуктовNONCLUSTERED index on (ProductNumber): this will allow ordered scans of product numbers

В таблице Sales.SpecialOffer_inmem есть один индекс HASH в (SpecialOfferID): уточняющие запросы специальных предложений находятся в самом сложном месте этой демонстрационной рабочей нагрузки.Sales.SpecialOffer_inmem has one HASH index on (SpecialOfferID): point lookups of special offers are in the critical part of the demo workload. Параметр bucket_count задан в размере 1 миллиона для обеспечения возможности роста в будущем.The bucket_count is sized at 1 million to allow for future growth.

Ссылок на таблицу Sales.SpecialOfferProduct_inmem в демонстрационной рабочей нагрузке нет, поэтому очевидная потребность в использовании индексов HASH в этой таблице с целью оптимизации рабочей нагрузки отсутствует — в (SpecialOfferID, ProductID) и (ProductID) используются индексы NONCLUSTERED.Sales.SpecialOfferProduct_inmem is not referenced in the demo workload, and thus there is no apparent need to use hash indexes on this table to optimize the workload - the indexes on (SpecialOfferID, ProductID) and (ProductID) are NONCLUSTERED.

Обратите внимание, что некоторые из приведенных выше параметров bucket_counts имеют слишком большое значение, но не параметры bucket_count для индексов в таблицах SalesOrderHeader_inmem и SalesOrderDetail_inmem: они заданы в размере 10 миллионов заказов на продажу.Notice that in the above some of the bucket_counts are over-sized, but not the bucket_counts for the indexes on SalesOrderHeader_inmem and SalesOrderDetail_inmem: they are sized for just 10 million sales orders. Сделано это было для того, чтобы обеспечить возможность установки образца в системах с небольшим объемом памяти, хотя в этих случаях демонстрационная рабочая нагрузка будет завершаться ошибкой из-за нехватки памяти.This was done to allow installing the sample on systems with low memory availability, although in those cases the demo workload will fail with out-of-memory. Если все же требуется обрабатывать намного больше, чем 10 миллионов заказов, то можно задать соответствующие значения для числа контейнеров.If you do want to scale well beyond 10 million sales orders, feel free to increase the bucket counts accordingly.

Соображения по использованию памятиConsiderations for memory utilization

Использование памяти в примере базы данных до и после выполнения демонстрационной рабочей нагрузки обсуждается в разделе Использование памяти оптимизированными для памяти таблицами.Memory utilization in the sample database, both before and after running the demo workload, is discussed in the Section Memory utilization for the memory-optimized tables.

Хранимые процедуры, добавляемые образцомStored Procedures added by the sample

Две основные хранимые процедуры для вставки заказов на продажу и обновления сведений о доставке:The two key stored procedures for inserting sales order and updating shipping details are as follows:

  • Sales.usp_InsertSalesOrder_inmemSales.usp_InsertSalesOrder_inmem

    • Вставляет новые заказы на продажу в базу данных и выдает SalesOrderID для вставленных заказов на продажу.Inserts a new sales order in the database and outputs the SalesOrderID for that sales order. В качестве входных параметров эта хранимая процедура использует данные из заголовка заказа на продажу, а также указанные в заказе линейные элементы.As input parameters it takes details for the sales order header, as well as the line items in the order.

    • Выходной параметр:Output parameter:

      • @SalesOrderID int — SalesOrderID для только что вставленного заказа на продажу.@SalesOrderID int - the SalesOrderID for the sales order that was just inserted
    • Входные параметры (обязательные):Input parameters (required):

      • @DueDate datetime2@DueDate datetime2

      • @CustomerID int@CustomerID int

      • @BillToAddressID [int]@BillToAddressID [int]

      • @ShipToAddressID [int]@ShipToAddressID [int]

      • @ShipMethodID [int]@ShipMethodID [int]

      • @SalesOrderDetails Sales.SalesOrderDetailType_inmem — параметр табличного значения (TVP), содержащий элементы строки заказа@SalesOrderDetails Sales.SalesOrderDetailType_inmem - table-valued parameter (TVP) that contains the line items of the order

    • Входные параметры (необязательные):Input parameters (optional):

      • @Status [tinyint]@Status [tinyint]

      • @OnlineOrderFlag [bit]@OnlineOrderFlag [bit]

      • @PurchaseOrderNumber [nvarchar](25)@PurchaseOrderNumber [nvarchar](25)

      • @AccountNumber [nvarchar](15)@AccountNumber [nvarchar](15)

      • @SalesPersonID [int]@SalesPersonID [int]

      • @TerritoryID [int]@TerritoryID [int]

      • @CreditCardID [int]@CreditCardID [int]

      • @CreditCardApprovalCode [varchar](15)@CreditCardApprovalCode [varchar](15)

      • @CurrencyRateID [int]@CurrencyRateID [int]

      • @Comment nvarchar(128)@Comment nvarchar(128)

  • Sales.usp_UpdateSalesOrderShipInfo_inmemSales.usp_UpdateSalesOrderShipInfo_inmem

    • Обновляет сведения о доставке для данного заказа на продажу.Update the shipping information for a given sales order. Также обновляются сведения о доставке для всех линейных элементов заказа на продажу.This will also update the shipping information for all line items of the sales order.

    • Это процедура-оболочка для скомпилированных в собственном коде хранимых процедур Sales.usp_UpdateSalesOrderShipInfo_native, содержащих логику повтора для обработки (непредвиденных) возможных конфликтов, возникающих при обновлении одного заказа выполняющимися одновременно транзакциями.This is a wrapper procedure for the natively compiled stored procedures Sales.usp_UpdateSalesOrderShipInfo_native with retry logic to deal with (unexpected) potential conflicts with concurrent transactions updating the same order. Дополнительные сведения о логике повтора см. в этом разделе электронной документации.For more information about retry logic see the Books Online topic here.

  • Sales.usp_UpdateSalesOrderShipInfo_nativeSales.usp_UpdateSalesOrderShipInfo_native

    • Это скомпилированная в собственном коде хранимая процедура, которая фактически выполняет обновление сведений о доставке.This is the natively compiled stored procedure that actually processes the update to the shipping information. Она вызывается из хранимой процедуры-оболочки Sales.usp_UpdateSalesOrderShipInfo_inmem.It is means to be called from the wrapper stored procedure Sales.usp_UpdateSalesOrderShipInfo_inmem. Если клиент может обрабатывать сбои и имеет логику повтора, то эту процедуру можно вызывать напрямую без использования хранимой процедуры-оболочки.If the client can deal with failures and implements retry logic, you can call this procedure directly, rather than using the wrapper stored procedure.

В демонстрационной рабочей нагрузке используется приведенная далее хранимая процедура.The following stored procedure is used for the demo workload.

  • Demo.usp_DemoResetDemo.usp_DemoReset

    • Выполняет сброс демонстрации путем повторного заполнения таблиц SalesOrderHeader и SalesOrderDetail.Resets the demo by emptying and reseeding the SalesOrderHeader and SalesOrderDetail tables.

Следующие хранимые процедуры используются для вставки в оптимизированные для памяти таблицы и удаления из них с обеспечением доменной и ссылочной целостности.The following stored procedures are used for inserting in and deleting from memory-optimized tables while guaranteeing domain and referential integrity.

  • Production.usp_InsertProduct_inmemProduction.usp_InsertProduct_inmem

  • Production.usp_DeleteProduct_inmemProduction.usp_DeleteProduct_inmem

  • Sales.usp_InsertSpecialOffer_inmemSales.usp_InsertSpecialOffer_inmem

  • Sales.usp_DeleteSpecialOffer_inmemSales.usp_DeleteSpecialOffer_inmem

  • Sales.usp_InsertSpecialOfferProduct_inmemSales.usp_InsertSpecialOfferProduct_inmem

Наконец, следующая хранимая процедура используется для проверки доменной и ссылочной целостности.Finally the following stored procedure is used to verify domain and referential integrity.

  1. dbo.usp_ValidateIntegritydbo.usp_ValidateIntegrity

    • Необязательный параметр: @object_id — идентификатор объекта для проверки целостности.Optional parameter: @object_id - ID of the object to validate integrity for

    • Эта процедура берет правила целостности, соответствие которым необходимо проверить, из таблиц dbo.DomainIntegrity, dbo.ReferentialIntegrity и dbo.UniqueIntegrity — образец заполняет эти таблицы с учетом проверочных ограничений, ограничений внешнего ключа и ограничений уникальности, которые имеются в исходных таблицах из базы данных AdventureWorks.This procedure relies on the tables dbo.DomainIntegrity, dbo.ReferentialIntegrity, and dbo.UniqueIntegrity for the integrity rules that need to be verified - the sample populates these tables based on the check, foreign key, and unique constraints that exist for the original tables in the AdventureWorks database.

    • Для формирования кода T-SQL, который нужен для выполнения проверок целостности, используются вспомогательные процедуры dbo.usp_GenerateCKCheck, dbo.usp_GenerateFKCheck и dbo.GenerateUQCheck.It relies on the helper procedures dbo.usp_GenerateCKCheck, dbo.usp_GenerateFKCheck, and dbo.GenerateUQCheck to generate the T-SQL needed for performing the integrity checks.

Performance Measurements using the Demo WorkloadPerformance Measurements using the Demo Workload

Ostress — это средство командной строки, разработанное группой поддержки Майкрософт CSS SQL Server.Ostress is a command-line tool that was developed by the Microsoft CSS SQL Server support team. С его помощью можно одновременно выполнять запросы или хранимые процедуры.This tool can be used to execute queries or run stored procedures in parallel. Можно задать количество потоков для параллельного выполнения данной инструкции T-SQL, а также можно указать, сколько раз следует выполнить инструкцию в этом потоке. Программа ostress запустит потоки и выполнит инструкцию во всех потоках одновременно.You can configure the number of threads to run a given T-SQL statement in parallel, and you can specify how many times the statement should be executed on this thread; ostress will spin up the threads and execute the statement on all threads in parallel. После завершения выполнения для всех потоков программа ostress сообщит время, которое потребовалось на завершение выполнения всеми потоками.After execution finishes for all threads, ostress will report the time taken for all threads to finish execution.

Установка ostressInstalling ostress

Программа Ostress устанавливается как часть пакета Report Markup Language (RML) Utilities. Ее нельзя установить отдельно.Ostress is installed as part of the Report Markup Language (RML) Utilities; there is no standalone installation for ostress.

Действия по установкеInstallation steps:

  1. Скачайте и запустите установочный пакет x64 RML Utilities со следующей страницы: Загрузить RML для SQL ServerDownload and run the x64 installation package for the RML utilities from the following page: Download RML for SQL Server

  2. Если появится диалоговое окно, в котором будет указано, что некоторые файлы используются, нажмите кнопку "Продолжить".If there is a dialog box saying certain files are in use, click 'Continue'

Запуск ostressRunning ostress

Программа ostress запускается из командной строки.Ostress is run from the command-line prompt. Удобнее всего запускать это средство из командной строки «RML Cmd Prompt», которая устанавливается как часть пакета RML Utilities.It is most convenient to run the tool from the "RML Cmd Prompt", which is installed as part of the RML Utilities.

Чтобы открыть RML Cmd Prompt, выполните следующие инструкции:To open the RML Cmd Prompt follow these instructions:

В Windows Server 2012 [R2], а также в Windows 8 и 8.1 откройте меню "Пуск", нажав клавишу Windows, и введите "rml".In Windows Server 2012 [R2] and in Windows 8 and 8.1, open the start menu by clicking the Windows key, and type 'rml'. Щелкните RML Cmd Prompt в результатах поиска.Click on "RML Cmd Prompt", which will be in the list of search results.

Удостоверьтесь в том, что командная строка находится в установочной папке RML Utilities.Ensure that the command prompt is located in the RML Utilities installation folder.

Параметры командной строки для программы ostress отображаются при запуске ostress.exe без каких-либо параметров.The command-line options for ostress can be seen when simply running ostress.exe without any command-line options. Основные параметры, которые можно использовать при запуске программы ostress для этого образца:The main options to consider for running ostress with this sample are:

  • -S — имя экземпляра Microsoft SQL Server для подключения.-S name of Microsoft SQL Server instance to connect to

  • -E — использование проверки подлинности Windows для подключения (по умолчанию). При использовании проверки подлинности SQL Server задайте параметры -U и -P, чтобы указать имя пользователя и пароль соответственно-E use Windows authentication to connect (default); if you use SQL Server authentication, use the options -U and -P to specify the username and password, respectively

  • -d имя базы данных (в этом случае AdventureWorks2014)-d name of the database, for this example AdventureWorks2014

  • -Q выполняемая инструкция T-SQL-Q the T-SQL statement to be executed

  • -n количество соединений, обрабатывающих каждый входной файл/запрос-n number of connections processing each input file/query

  • -r количество итераций для каждого соединения, выполняющих каждый входной файл/запрос-r the number of iterations for each connection to execute each input file/query

Демонстрационная рабочая нагрузкаDemo Workload

Главная хранимая процедура, используемая в демонстрационной рабочей нагрузке, — Sales.usp_InsertSalesOrder_inmem/ondisk.The main stored procedure used in the demo workload is Sales.usp_InsertSalesOrder_inmem/ondisk. Приведенный далее скрипт формирует возвращающий табличное значение параметр с образцом данных и вызывает процедуру для вставки заказа на продажу с пятью линейными элементами.The script in the below constructs a table-valued parameter (TVP) with sample data, and calls the procedure to insert a sales order with five line items.

Средство ostress служит для параллельного выполнения вызовов хранимых процедур с целью имитации одновременной вставки заказов на продажу клиентами.The ostress tool is used to execute the stored procedure calls in parallel, to simulate clients inserting sales orders concurrently.

Сбрасывайте образец после каждого использования, выполняя Demo.usp_DemoReset.Reset the demo after each stress run executing Demo.usp_DemoReset. Эта процедура удаляет строки из оптимизированных для памяти таблиц, усекает размещенные на диске таблицы и выполняет контрольную точку базы данных.This procedure deletes the rows in the memory-optimized tables, truncates the disk-based tables, and executes a database checkpoint.

Для имитации рабочей нагрузки по обработке заказов на продажу параллельно выполняется следующий скрипт.The following script is executed concurrently to simulate a sales order processing workload:

DECLARE   
      @i int = 0,   
      @od Sales.SalesOrderDetailType_inmem,   
      @SalesOrderID int,   
      @DueDate datetime2 = sysdatetime(),   
      @CustomerID int = rand() * 8000,   
      @BillToAddressID int = rand() * 10000,   
      @ShipToAddressID int = rand() * 10000,   
      @ShipMethodID int = (rand() * 5) + 1;   
  
INSERT INTO @od   
SELECT OrderQty, ProductID, SpecialOfferID   
FROM Demo.DemoSalesOrderDetailSeed   
WHERE OrderID= cast((rand()*106) + 1 as int);   
  
WHILE (@i < 20)   
BEGIN;   
      EXEC Sales.usp_InsertSalesOrder_inmem @SalesOrderID OUTPUT, @DueDate, @CustomerID, @BillToAddressID, @ShipToAddressID, @ShipMethodID, @od;   
      SET @i += 1   
END

При выполнении этого скрипта каждый образец сформированного заказа вставляется 20 раз через 20 хранимых процедур, выполняемых в цикле WHILE.With this script, each sample order that is constructed is inserted 20 times, through 20 stored procedures executed in a WHILE loop. Эти циклы используются для учета того факта, что для формирования образца заказа используется база данных.The loop is used to account for the fact that the database is used to construct the sample order. В стандартных рабочих средах вставляемый заказ на продажу формируется приложением промежуточного уровня.In typical production environments, the mid-tier application will construct the sales order to be inserted.

Приведенный выше скрипт вставляет заказы на продажу в оптимизированные для памяти таблицы.The above script inserts sales orders into memory-optimized tables. Чтобы получить скрипт для вставки заказов на продажу в таблицы, размещенные на диске, нужно заменить два вхождения _inmem на _ondisk.The script to insert sales orders into disk-based tables is derived by replacing the two occurrences of '_inmem' with '_ondisk'.

Мы воспользуемся средством ostress для выполнения скриптов с использованием нескольких параллельных соединений.We will use the ostress tool to execute the scripts using several concurrent connections. Чтобы определить количество соединений, укажем параметр -n, а параметр -r — для определения числа выполнений скрипта в каждом соединении.We will use the parameter '-n' to control the number of connections, and the parameter 'r' to control how many times the script is executed on each connection.

Выполнение рабочей нагрузкиRunning the Workload

Чтобы выполнить масштабное тестирование, вставим 10 миллионов заказов на продажу с использованием 100 соединений.To test at scale we insert 10 million sales orders, using 100 connections. Этот тест работает относительно неплохо на не очень мощном сервере (например, с 8 физическими и 16 логическими ядрами) с базовым хранилищем SSD для журнала.This test performs reasonably on a modest server (e.g., 8 physical, 16 logical cores), and basic SSD storage for the log. Если производительность теста на вашем оборудовании неудовлетворительна, ознакомьтесь с разделом Устранение неполадок тестов, которые выполняются медленно. Если требуется снизить нагрузку для этого теста, уменьшите количество соединений, изменив параметр -n.If the test does not perform well on your hardware, take look at the Section Troubleshooting slow-running tests.If you want to reduce the level of stress for this test, lower the number of connections by changing the parameter '-n'. Например, чтобы снизить число соединений до 40, замените параметр -n100 на -n40.For example to lower the connection count to 40, change the parameter '-n100' to '-n40'.

В качестве меры производительности рабочей нагрузки служит затраченное время, сообщаемое программой ostress.exe после выполнения рабочей нагрузки.As a performance measure for the workload we use the elapsed time as reported by ostress.exe after running the workload.

В приведенных ниже инструкциях и измерениях используется рабочая нагрузка, которая вставляет 10 миллионов заказов на продажу.The below instructions and measurements use a workload that inserts 10 million sales orders. Инструкции по выполнению более легкой рабочей нагрузки, вставляющей 1 миллион заказов на продажу, см. в файле In-Memory OLTP\readme.txt из архива SQLServer2016CTP3Samples.zip.For instructions to run a scaled-down workload inserting 1 million sales orders, see the instructions in 'In-Memory OLTP\readme.txt' that is part of the SQLServer2016CTP3Samples.zip archive.

Таблицы, оптимизированные для памятиMemory-optimized tables

Начнем с выполнения рабочей нагрузки в оптимизированных для памяти таблицах.We will start by running the workload on memory-optimized tables. Следующая команда открывает 100 потоков, каждый из которых выполняет 5000 итераций.The following command opens 100 threads, each running for 5,000 iterations. Каждая итерация вставляет 20 заказов на продажу в отдельных транзакциях.Each iteration inserts 20 sales orders in separate transactions. В каждой итерации есть 20 вставок для компенсации использования базы данных, для формирования вставляемых данных.There are 20 inserts per iteration to compensate for the fact that the database is used to generate the data to be inserted. Это дает всего 20 * 5000 * 100 = 10 000 000 вставок заказов на продажу.This yield a total of 20 * 5,000 * 100 = 10,000,000 sales order inserts.

Откройте командную строку RML Cmd Prompt и выполните следующую команду:Open the RML Cmd Prompt, and execute the following command:

Нажмите кнопку «Копировать», чтобы скопировать команду, и вставьте ее в командную строку RML Utilities.Click the Copy button to copy the command, and paste it into the RML Utilities command prompt.

ostress.exe -n100 -r5000 -S. -E -dAdventureWorks2016CTP3 -q -Q"DECLARE @i int = 0, @od Sales.SalesOrderDetailType_inmem, @SalesOrderID int, @DueDate datetime2 = sysdatetime(), @CustomerID int = rand() * 8000, @BillToAddressID int = rand() * 10000, @ShipToAddressID int = rand() * 10000, @ShipMethodID int = (rand() * 5) + 1; INSERT INTO @od SELECT OrderQty, ProductID, SpecialOfferID FROM Demo.DemoSalesOrderDetailSeed WHERE OrderID= cast((rand()*106) + 1 as int); while (@i < 20) begin; EXEC Sales.usp_InsertSalesOrder_inmem @SalesOrderID OUTPUT, @DueDate, @CustomerID, @BillToAddressID, @ShipToAddressID, @ShipMethodID, @od; set @i += 1 end"  

Ее выполнение на одном тестовом сервере, общее число ядер в котором составляет 8 физических (16 логических), заняло 2 минуты 5 секунд.On one test server with a total number of 8 physical (16 logical) cores, this took 2 minutes and 5 seconds. Ее выполнение на втором тестовом сервере, общее число ядер в котором составляет 24 физических и 48 логических, заняло 1 минуту 0 секунд.On a second test server with 24 physical (48 logical) cores, this took 1 minute and 0 seconds.

Следите за использованием ЦП во время выполнения рабочей нагрузки (например, с помощью диспетчера задач).Observe the CPU utilization while the workload is running, for example using task manager. Вы увидите, что использование ЦП близко к 100 %.You will see that CPU utilization is close to 100%. Если это не так, то имеется узкое место в области ввода-вывода журнала (см. также раздел Устранение неполадок тестов, которые выполняются медленно).If this is not the case, you have a log IO bottleneck see also Troubleshooting slow-running tests.

Таблицы на дискеDisk-based tables

Следующая команда будет запускать рабочую нагрузку на дисковых таблицах.The following command will run the workload on disk-based tables. На выполнение этой рабочей нагрузки может уйти значительное время. Связано это главным образом с конфликтами кратковременных блокировок в системе.This workload may take a while to execute, which is largely due to latch contention in the system. В оптимизированной для памяти таблице нет кратковременных блокировок, поэтому она не страдает от этой проблемы.Memory-optimized table are latch-free and thus do not suffer from this problem.

Откройте командную строку RML Cmd Prompt и выполните следующую команду:Open the RML Cmd Prompt, and execute the following command:

Нажмите кнопку «Копировать», чтобы скопировать команду, и вставьте ее в командную строку RML Utilities.Click the Copy button to copy the command, and paste it into the RML Utilities command prompt.

ostress.exe -n100 -r5000 -S. -E -dAdventureWorks2016CTP3 -q -Q"DECLARE @i int = 0, @od Sales.SalesOrderDetailType_ondisk, @SalesOrderID int, @DueDate datetime2 = sysdatetime(), @CustomerID int = rand() * 8000, @BillToAddressID int = rand() * 10000, @ShipToAddressID int = rand() * 10000, @ShipMethodID int = (rand() * 5) + 1; INSERT INTO @od SELECT OrderQty, ProductID, SpecialOfferID FROM Demo.DemoSalesOrderDetailSeed WHERE OrderID= cast((rand()*106) + 1 as int); while (@i < 20) begin; EXEC Sales.usp_InsertSalesOrder_ondisk @SalesOrderID OUTPUT, @DueDate, @CustomerID, @BillToAddressID, @ShipToAddressID, @ShipMethodID, @od; set @i += 1 end"  

Ее выполнение на одном тестовом сервере, общее число ядер в котором составляет 8 физических и 16 логических, заняло 41 минуту 25 секунд.On one test server with a total number of 8 physical (16 logical) cores, this took 41 minutes and 25 seconds. Ее выполнение на втором тестовом сервере, общее число ядер в котором составляет 24 физических и 48 логических, заняло 52 минуты 16 секунд.On a second test server with 24 physical (48 logical) cores, this took 52 minutes and 16 seconds.

Основным фактором, определяющим разницу в производительности между оптимизированными для памяти таблицами и таблицами, размещенными на диске, в этом тесте является то, что при использовании таблиц, размещенных на диске, SQL Server не может полностью использовать возможности ЦП.The main factor in the performance difference between memory-optimized tables and disk-based tables in this test is the fact that when using disk-based tables, SQL Server cannot not fully utilize the CPU. Причина состоит в конфликтах по кратковременным блокировкам: выполняющиеся одновременно транзакции пытаются производить запись на одну и ту же страницу данных. Кратковременные блокировки используются для обеспечения того, что только одна транзакция будет осуществлять запись на страницу в определенный момент времени.The reason is latch contention: concurrent transactions are attempting to write to the same data page; latches are used to ensure only one transaction at a time can write to a page. Подсистема выполняющейся в памяти OLTP не использует кратковременные блокировки, а строки данных не формируют страницы.The In-Memory OLTP engine is latch-free, and data rows are not organized in pages. Поэтому транзакции, выполняемые одновременно, не блокируют друг друга, что позволяет SQL Server в полном объеме использовать ресурсы ЦП.Thus, concurrent transactions do not block each other's inserts, thus enabling SQL Server to fully utilize the CPU.

Отследить использование ЦП можно во время выполнения рабочей нагрузки (например, с помощью диспетчера задач).You can observe the CPU utilization while the workload is running, for example using task manager. Вы увидите, что при использовании таблиц, размещенных на диске, использование ЦП далеко от 100 %.You will see with disk-based tables the CPU utilization is far from 100%. В тестовой конфигурации с 16 логическими процессорами использование находится в районе 24 %.On a test configuration with 16 logical processors, the utilization would hover around 24%.

Кроме того, с помощью системного монитора можно просмотреть количество ожиданий, связанных с кратковременными блокировками (счетчик производительности \SQL Server:Latches\Latch Waits/sec).Optionally, you can view the number of latch waits per second using Performance Monitor, with the performance counter '\SQL Server:Latches\Latch Waits/sec'.

Сброс образцаResetting the demo

Чтобы сбросить образец, откройте командную строку RML Cmd Prompt и выполните следующую команду:To reset the demo, open the RML Cmd Prompt, and execute the following command:

ostress.exe -S. -E -dAdventureWorks2016CTP3 -Q"EXEC Demo.usp_DemoReset"  

В зависимости от оборудования выполнение данного примера может занять несколько минут.Depending on the hardware, this may take a few minutes to run.

Рекомендуется выполнять сброс после каждого выполнения.We recommend a reset after every demo run. Поскольку рабочая нагрузка состоит только из вставки, каждое выполнение будет потреблять больше памяти, поэтому необходимо выполнять сброс, чтобы не задействовать всю память.Because this workload is insert-only, each run will consume more memory, and thus a reset is required to prevent running out of memory. Количество используемой после запуска памяти описывается в разделе Использование памяти после выполнения рабочей нагрузки.The amount of memory consumed after a run is discussed in Section Memory utilization after running the workload.

Устранение неполадок тестов, которые выполняются медленноTroubleshooting slow-running tests

Результаты теста, как правило, зависят от оборудования и уровня параллелизма во время его выполнения.Test results will typically vary with hardware, and also the level of concurrency used in the test run. Необходимо проверить несколько моментов, если результаты отличаются от ожидаемых.A couple of things to look for if the results are not as expected:

  • Число параллельных транзакций. При выполнении рабочей нагрузки в одном потоке рост производительности от использования выполняющейся в памяти OLTP, скорее всего, будет менее чем двукратным.Number of concurrent transactions: When running the workload on a single thread, performance gain with In-Memory OLTP will likely be less than 2X. Конфликты кратковременных блокировок становятся большой проблемой только при высоком уровне параллелизма.Latch contention is only a big problem if there is a high level of concurrency.

  • Небольшое количество процессоров, доступных для SQL Server. Это означает, что в системе будет низкий уровень параллелизма, так как число параллельно выполняемых транзакций будет равно числу ядер, доступных для SQL.Low number of cores available to SQL Server: This means there will be a low level of concurrency in the system, as there can only be as many concurrently executing transactions as there are cores available to SQL.

    • Симптом: высокий процент использования ЦП при выполнении рабочей нагрузки по таблицам, размещенным на диске, означает, что объем состязаний невелик. Это указывает на недостаток параллелизма.Symptom: if the CPU utilization is high when running the workload on disk-based tables, this means there is not a lot of contention, pointing to a lack of concurrency.
  • Скорость работы диска, где расположен журнал. Если диск, на котором расположен журнал, не успевает за пропускной способностью транзакций в системе, формируется узкое место рабочей нагрузки, связанное с вводом-выводом журнала.Speed of the log drive: If the log drive cannot keep up with the level of transaction throughput in the system, the workload becomes bottlenecked on log IO. Несмотря на то, что в выполняющейся в памяти OLTP ведение журнала стало более эффективным, если ввод-вывод журнала является узким местом, потенциальный прирост производительности будет ограничен.Although logging is more efficient with In-Memory OLTP, if log IO is a bottleneck, the potential performance gain is limited.

    • Симптом: если при выполнении рабочей нагрузки в оптимизированных для памяти таблицах использование ЦП не приближается к 100 % или подвержено очень высоким колебаниям, то, возможно, существует узкое место, связанное с вводом-выводом журнала.Symptom: if the CPU utilization is not close to 100% or is very spiky when running the workload on memory-optimized tables, it is possible there is a log IO bottleneck. Проверить это можно, открыв системный монитор и оценив длину очереди для диска журнала.This can be confirmed by opening Resource Monitor and looking at the queue length for the log drive.

Использование памяти и места на диске образцомMemory and Disk Space Utilization in the Sample

Ниже описано, что следует ожидать в отношении использования памяти и места на диске для образца базы данных.In the below we describe what to expect in terms of memory and disk space utilization for the sample database. Также приводятся результаты, отмеченные на тестовом сервере с 16 логическими ядрами.We also show the results we have seen in on a test server with 16 logical cores.

Использование памяти оптимизированными для памяти таблицамиMemory utilization for the memory-optimized tables

Общее использование базы данныхOverall utilization of the database

Следующий запрос может быть использован для получения общей загрузки памяти для системы выполняющейся в памяти OLTP.The following query can be used to obtain the total memory utilization for In-Memory OLTP in the system.

SELECT type  
   , name  
, pages_kb/1024 AS pages_MB   
FROM sys.dm_os_memory_clerks WHERE type LIKE '%xtp%'  

Моментальный снимок сразу после создания базы данных:Snapshot after the database has just been created:

typetype namename pages_MBpages_MB
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 9494
MEMORYCLERK_XTPMEMORYCLERK_XTP DB_ID_5DB_ID_5 877877
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00

Клерки памяти по умолчанию содержат структуры памяти во всей системе и являются относительно небольшими.The default memory clerks contain system-wide memory structures and are relatively small. Клерк памяти, предназначенный для пользовательской базы данных (в данном случае это база данных с идентификатором 5), составляет примерно 900 МБ.The memory clerk for the user database, in this case database with ID 5, is about 900 MB.

Использование памяти на таблицуMemory utilization per table

С помощью следующего запроса можно получить объем использования памяти для отдельных таблиц и их индексов.The following query can be used to drill down into the memory utilization of the individual tables and their indexes:

SELECT object_name(t.object_id) AS [Table Name]  
     , memory_allocated_for_table_kb  
 , memory_allocated_for_indexes_kb  
FROM sys.dm_db_xtp_table_memory_stats dms JOIN sys.tables t   
ON dms.object_id=t.object_id  
WHERE t.type='U'  

В таблице ниже приведены результаты выполнения этого запроса для свежей установки образца.The following table displays the results of this query for a fresh installation of the sample:

Имя таблицыTable Name memory_allocated_for_table_kbmemory_allocated_for_table_kb memory_allocated_for_indexes_kbmemory_allocated_for_indexes_kb
SpecialOfferProduct_inmemSpecialOfferProduct_inmem 6464 38403840
DemoSalesOrderHeaderSeedDemoSalesOrderHeaderSeed 19841984 55045504
SalesOrderDetail_inmemSalesOrderDetail_inmem 1531615316 663552663552
DemoSalesOrderDetailSeedDemoSalesOrderDetailSeed 6464 1043210432
SpecialOffer_inmemSpecialOffer_inmem 33 81928192
SalesOrderHeader_inmemSalesOrderHeader_inmem 71687168 147456147456
Product_inmemProduct_inmem 124124 1235212352

Как видите, размер таблиц весьма невелик. SalesOrderHeader_inmem занимает примерно 7 МБ, а SalesOrderDetail_inmem — примерно 15 МБ.As you can see the tables are fairly small: SalesOrderHeader_inmem is about 7 MB, and SalesOrderDetail_inmem is about 15 MB in size.

Поразительнее всего здесь размер памяти, выделенной для индексов, в сравнении с размером данных таблиц.What is striking here is the size of the memory allocated for indexes, compared to the size of the table data. Причина этого заключается в том, что размер индексов HASH в образце задан для данных большего объема.That is because the hash indexes in the sample are pre-sized for a larger data size. Обратите внимание, что индексы HASH имеют фиксированный размер, поэтому их размер не будет расти вместе с размером данных в таблице.Note that hash indexes have a fixed size, and thus their size will not grow with the size of data in the table.

Использование памяти после выполнения рабочей нагрузкиMemory utilization after running the workload

После вставки 10 миллионов заказов на продажу общий объем использованной памяти будет примерно таким:After insert 10 million sales orders, the all-up memory utilization looks similar to the following:

SELECT type  
, name  
, pages_kb/1024 AS pages_MB   
FROM sys.dm_os_memory_clerks WHERE type LIKE '%xtp%'  
typetype namename pages_MBpages_MB
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 146146
MEMORYCLERK_XTPMEMORYCLERK_XTP DB_ID_5DB_ID_5 73747374
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00

Как можно видеть, SQL Server использует чуть меньше 8 ГБ под оптимизированные для памяти таблицы и индексы из образца базы данных.As you can see, SQL Server is using a bit under 8 GB for the memory-optimized tables and indexes in the sample database.

Подробные данные об использовании памяти для каждой таблицы после одного выполнения:Looking at the detailed memory usage per table after one example run:

SELECT object_name(t.object_id) AS [Table Name]  
     , memory_allocated_for_table_kb  
 , memory_allocated_for_indexes_kb  
FROM sys.dm_db_xtp_table_memory_stats dms JOIN sys.tables t   
ON dms.object_id=t.object_id  
WHERE t.type='U'  
Имя таблицыTable Name memory_allocated_for_table_kbmemory_allocated_for_table_kb memory_allocated_for_indexes_kbmemory_allocated_for_indexes_kb
SalesOrderDetail_inmemSalesOrderDetail_inmem 51137615113761 663552663552
DemoSalesOrderDetailSeedDemoSalesOrderDetailSeed 6464 1036810368
SpecialOffer_inmemSpecialOffer_inmem 22 81928192
SalesOrderHeader_inmemSalesOrderHeader_inmem 15756791575679 147456147456
Product_inmemProduct_inmem 111111 1203212032
SpecialOfferProduct_inmemSpecialOfferProduct_inmem 6464 37123712
DemoSalesOrderHeaderSeedDemoSalesOrderHeaderSeed 19841984 55045504

Как видите, общий объем данных составляет примерно 6,5 ГБ.We can see a total of about 6.5 GB of data. Обратите внимание, что индексы в таблицах SalesOrderHeader_inmem и SalesOrderDetail_inmem имеют тот же размер, что и индексы до вставки заказов на продажу.Notice that the size of the indexes on the table SalesOrderHeader_inmem and SalesOrderDetail_inmem is the same as the size of the indexes before inserting the sales orders. Размер индексов не изменился, потому что в обеих таблицах используются индексы HASH, а они являются статическими.The index size did not change because both tables are using hash indexes, and hash indexes are static.

После сброса образцаAfter demo reset

Для сброса образца используется хранимая процедура Demo.usp_DemoReset.The stored procedure Demo.usp_DemoReset can be used to reset the demo. Она удаляет данные из таблиц SalesOrderHeader_inmem и SalesOrderDetail_inmem и вносит в них данные из исходных таблиц SalesOrderHeader и SalesOrderDetail.It deletes the data in the tables SalesOrderHeader_inmem and SalesOrderDetail_inmem, and re-seeds the data from the original tables SalesOrderHeader and SalesOrderDetail.

Теперь, даже после удаления строк из таблиц, это не означает, что память сразу же будет освобождена.Now, even though the rows in the tables have been deleted, this does not mean that memory is reclaimed immediately. SQL Server возвращает память от удаленных строк из оптимизированных для памяти таблиц в фоновом режиме по мере необходимости.SQL Server reclaims memory from deleted rows in memory-optimized tables in the background, as needed. Вы увидите, что сразу же после сброса образца при отсутствии в системе рабочей нагрузки по обработке транзакций память от удаленных строк остается занятой.You will see that immediately after demo reset, with no transactional workload on the system, memory from deleted rows is not yet reclaimed:

SELECT type  
, name  
, pages_kb/1024 AS pages_MB   
FROM sys.dm_os_memory_clerks WHERE type LIKE '%xtp%'  
typetype namename pages_MBpages_MB
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 22612261
MEMORYCLERK_XTPMEMORYCLERK_XTP DB_ID_5DB_ID_5 73967396
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00

Это ожидаемо: память будет освобождаться при выполнении транзакционной рабочей нагрузки.This is expected: memory will be reclaimed when the transactional workload is running.

Если снова запустить демонстрационную рабочую нагрузку, то первоначально объем использованной памяти понизится по мере очистки удаленных ранее строк.If you start a second run of the demo workload you will see the memory utilization decrease initially, as the previously deleted rows are cleaned up. В определенный момент объем использованной памяти снова начнет увеличиваться вплоть до завершения выполнения рабочей нагрузки.At some point the memory size will increase again, until the workload finishes. После вставки 10 миллионов строк после сброса демонстрации загрузка памяти будет очень похожа на загрузку после первоначального запуска.After inserting 10 million rows after demo reset, the memory utilization will be very similar to the utilization after the first run. Пример:For example:

SELECT type  
, name  
, pages_kb/1024 AS pages_MB   
FROM sys.dm_os_memory_clerks WHERE type LIKE '%xtp%'  
typetype namename pages_MBpages_MB
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 18631863
MEMORYCLERK_XTPMEMORYCLERK_XTP DB_ID_5DB_ID_5 73907390
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00
MEMORYCLERK_XTPMEMORYCLERK_XTP По умолчаниюDefault 00

Использование диска оптимизированными для памяти таблицамиDisk utilization for memory-optimized tables

Общий размер на диске файлов контрольных точек базы данных в данное время можно узнать, выполнив следующий запрос:The overall on-disk size for the checkpoint files of a database at a given time can be found using the query:

SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]  
FROM sys.filegroups f JOIN sys.database_files df   
   ON f.data_space_id=df.data_space_id  
WHERE f.type=N'FX'  
  

Начальное состояниеInitial state

Когда образцы файловой группы и оптимизированных для памяти таблиц создаются первоначально, формируется несколько файлов контрольных точек и система начинает заполнять эти файлы — их число зависит от количества логических процессоров в системе.When the sample filegroup and sample memory-optimized tables are created initially, a number of checkpoint files are pre-created and the system starts filling the files - the number of checkpoint files pre-created depends on the number of logical processors in the system. Поскольку изначально образец очень мал, предварительно созданные файлы будут вначале по большей части пустыми.As the sample is initially very small, the pre-created files will be mostly empty after initial create.

Ниже приведен начальный размер на диске для образца на компьютере с 16 логическими процессорами.The following code shows the initial on-disk size for the sample on a machine with 16 logical processors:

SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]  
FROM sys.filegroups f JOIN sys.database_files df   
   ON f.data_space_id=df.data_space_id  
WHERE f.type=N'FX'  
Размер на диске в МБOn-disk size in MB
23122312

Как видите, существует большая разница между размером файлов контрольных точек на диске, который составляет 2,3 ГБ, и фактическим размером данных, равным почти 30 МБ.As you can see, there is a big discrepancy between the on-disk size of the checkpoint files, which is 2.3 GB, and the actual data size, which is closer to 30 MB.

Чтобы лучше разобраться, откуда взялся такой показатель использования дискового пространства, можно выполнить следующий запрос.Looking closer at where the disk-space utilization comes from, you can use the following query. Размер на диске, возвращаемый этим запросом, является приблизительным для файлов, находящихся в состоянии 5 (REQUIRED FOR BACKUP/HA), 6 (IN TRANSITION TO TOMBSTONE) или 7 (TOMBSTONE).The size on disk returned by this query is approximate for files with state in 5 (REQUIRED FOR BACKUP/HA), 6 (IN TRANSITION TO TOMBSTONE), or 7 (TOMBSTONE).

SELECT state_desc  
 , file_type_desc  
 , COUNT(*) AS [count]  
 , SUM(CASE  
   WHEN state = 5 AND file_type=0 THEN 128*1024*1024  
   WHEN state = 5 AND file_type=1 THEN 8*1024*1024  
   WHEN state IN (6,7) THEN 68*1024*1024  
   ELSE file_size_in_bytes  
    END) / 1024 / 1024 AS [on-disk size MB]   
FROM sys.dm_db_xtp_checkpoint_files  
GROUP BY state, state_desc, file_type, file_type_desc  
ORDER BY state, file_type  

Для первоначального состояния образца результат будет выглядеть примерно как для сервера с 16 логическими процессорами:For the initial state of the sample, the result will look something like for a server with 16 logical processors:

state_descstate_desc file_type_descfile_type_desc countcount Размер на диске в МБon-disk size MB
PRECREATEDPRECREATED DATADATA 1616 20482048
PRECREATEDPRECREATED DELTADELTA 1616 128128
UNDER CONSTRUCTIONUNDER CONSTRUCTION DATADATA 11 128128
UNDER CONSTRUCTIONUNDER CONSTRUCTION DELTADELTA 11 88

Как видите, большая часть объема используется воссозданными файлами данных и разностными файлами.As you can see, most of the space is used by precreated data and delta files. SQL Server предварительно создает одну пару файлов (файл данных и разностный файл) на логический процессор.SQL Server pre-created one pair of (data, delta) files per logical processor. Кроме того, файлы данных имеют заранее заданный размер в 128 МБ, а разностные файлы — в 8 МБ, чтобы сделать вставку данных в эти файлы более эффективной.In addition, data files are pre-sized at 128 MB, and delta files at 8 MB, in order to make inserting data into these files more efficient.

Сами данные из оптимизированных для памяти таблиц находятся в одном файле данных.The actual data in the memory-optimized tables is in the single data file.

После выполнения рабочей нагрузкиAfter running the workload

После единичного запуска теста, производящего вставку 10 миллионов заказов на продажу, общий размер на диске выглядит примерно так (для 16-ядерного тестового сервера):After a single test run that inserts 10 million sales orders, the overall on-disk size looks something like this (for a 16-core test server):

SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]  
FROM sys.filegroups f JOIN sys.database_files df   
   ON f.data_space_id=df.data_space_id  
WHERE f.type=N'FX'  
Размер на диске в МБOn-disk size in MB
88288828

Дисковый размер приближается к 9 ГБ, что близко к размеру данных в памяти.The on-disk size is close to 9 GB, which comes close to the in-memory size of the data.

Более тщательное исследование размера файлов контрольных точек в различных состояниях.Looking more closely at the sizes of the checkpoint files across the various states:

SELECT state_desc  
 , file_type_desc  
 , COUNT(*) AS [count]  
 , SUM(CASE  
   WHEN state = 5 AND file_type=0 THEN 128*1024*1024  
   WHEN state = 5 AND file_type=1 THEN 8*1024*1024  
   WHEN state IN (6,7) THEN 68*1024*1024  
   ELSE file_size_in_bytes  
    END) / 1024 / 1024 AS [on-disk size MB]   
FROM sys.dm_db_xtp_checkpoint_files  
GROUP BY state, state_desc, file_type, file_type_desc  
ORDER BY state, file_type  
state_descstate_desc file_type_descfile_type_desc countcount Размер на диске в МБon-disk size MB
PRECREATEDPRECREATED DATADATA 1616 20482048
PRECREATEDPRECREATED DELTADELTA 1616 128128
UNDER CONSTRUCTIONUNDER CONSTRUCTION DATADATA 11 128128
UNDER CONSTRUCTIONUNDER CONSTRUCTION DELTADELTA 11 88

У нас по-прежнему имеется 16 пар предварительно созданных файлов, готовых по мере закрытия контрольных точек.We still have 16 pairs of pre-created files, ready to go as checkpoints are closed.

Одна пара находится в разработке и используется до тех пор, пока не будет закрыта текущая контрольная точка.There is one pair under construction, which is used until the current checkpoint is closed. Вместе с активными файлами контрольных точек это дает примерно 6,5 ГБ занятого дискового пространства для 5,5 ГБ данных в памяти.Along with the active checkpoint files this gives about 6.5 GB of disk utilization for 6.5 GB of data in memory. Вспомним, что индексы не сохраняются на диск, поэтому в данном случае общий размер на диске меньше, чем размер в памяти.Recall that indexes are not persisted on disk, and thus the overall size on disk is smaller than the size in memory in this case.

После сброса образцаAfter demo reset

После сброса образца место на диске не возвращается немедленно, если в системе отсутствует рабочая нагрузка по обработке транзакций и нет контрольных точек базы данных.After demo reset, disk space is not reclaimed immediately if there is no transactional workload on the system, and there are not database checkpoints. Для прохождения файлами контрольных точек через различные этапы с последующим их удалением должно произойти несколько событий контрольных точек и усечения журнала, чтобы инициировать слияние файлов контрольных точек, а также сборка мусора.For checkpoint files to be moved through their various stages and eventually be discarded, a number of checkpoints and log truncation events need to happen, to initiate merge of checkpoint files, as well as to initiate garbage collection. Это происходит автоматически при наличии в системе рабочей нагрузки по обработке транзакций [и создания обычных резервных копий журнала при использовании модели полного восстановления], но не тогда, когда система бездействует, как в нашем случае.These will happen automatically if you have a transactional workload in the system [and take regular log backups, in case you are using the FULL recovery model], but not when the system is idle, as in a demo scenario.

В этом примере после сброса образца можно наблюдать нечто похожее наIn the example, after demo reset, you may see something like

SELECT SUM(df.size) * 8 / 1024 AS [On-disk size in MB]  
FROM sys.filegroups f JOIN sys.database_files df   
   ON f.data_space_id=df.data_space_id  
WHERE f.type=N'FX'  
Размер на диске в МБOn-disk size in MB
1183911839

Почти 12 ГБ, что значительно больше чем 9 ГБ, которые мы имели до сброса образца.At nearly 12 GB, this is significantly more than the 9 GB we had before the demo reset. Связано это с тем, что были запущены слияния файлов контрольных точек, но некоторые цели слияния пока еще не установлены, а некоторые исходные файлы слияний пока еще не были очищены, что видно из нижеследующего.This is because some checkpoint file merges have been started, but some of the merge targets have not yet been installed, and some of the merge source files have not yet been cleaned up, as can be seen from the following:

SELECT state_desc  
 , file_type_desc  
 , COUNT(*) AS [count]  
 , SUM(CASE  
   WHEN state = 5 AND file_type=0 THEN 128*1024*1024  
   WHEN state = 5 AND file_type=1 THEN 8*1024*1024  
   WHEN state IN (6,7) THEN 68*1024*1024  
   ELSE file_size_in_bytes  
    END) / 1024 / 1024 AS [on-disk size MB]   
FROM sys.dm_db_xtp_checkpoint_files  
GROUP BY state, state_desc, file_type, file_type_desc  
ORDER BY state, file_type  
state_descstate_desc file_type_descfile_type_desc countcount Размер на диске в МБon-disk size MB
PRECREATEDPRECREATED DATADATA 1616 20482048
PRECREATEDPRECREATED DELTADELTA 1616 128128
ACTIVEACTIVE DATADATA 3838 51525152
ACTIVEACTIVE DELTADELTA 3838 13311331
MERGE TARGETMERGE TARGET DATADATA 77 896896
MERGE TARGETMERGE TARGET DELTADELTA 77 5656
MERGED SOURCEMERGED SOURCE DATADATA 1313 17721772
MERGED SOURCEMERGED SOURCE DELTADELTA 1313 455455

Цели слияния устанавливаются, а исходные файлы слияния удаляются по мере выполнения транзакций в системе.Merge targets are installed and merged source are cleaned up as transactional activity happens in the system.

После второго выполнения демонстрационной рабочей нагрузки с вставкой 10 миллионов заказов на продажу после сброса образца вы увидите, что файлы, сформированные во время первого выполнения рабочей нагрузки, были очищены.After a second run of the demo workload, inserting 10 million sales orders after the demo reset, you will see that the files constructed during the first run of the workload have been cleaned up. Приведенный выше запрос можно выполнить несколько раз во время выполнения рабочей нагрузки. Это позволит увидеть, как файлы контрольных точек проходят по различным этапам.If you run the above query several times while the workload is running, you can see the checkpoint files make their way through the various stages.

После второго выполнения рабочей нагрузки по вставке 10 миллионов заказов на продажу вы увидите, что объем использования дискового пространства будет почти такой же, хотя он и может немного отличаться, как после первого выполнения, поскольку система является по своей природе динамичной.After the second run of the workload insert 10 million sales orders you will see disk utilization very similar to, though not necessarily the same as after the first run, as the system is dynamic in nature. Пример:For example:

SELECT state_desc  
 , file_type_desc  
 , COUNT(*) AS [count]  
 , SUM(CASE  
   WHEN state = 5 AND file_type=0 THEN 128*1024*1024  
   WHEN state = 5 AND file_type=1 THEN 8*1024*1024  
   WHEN state IN (6,7) THEN 68*1024*1024  
   ELSE file_size_in_bytes  
    END) / 1024 / 1024 AS [on-disk size MB]   
FROM sys.dm_db_xtp_checkpoint_files  
GROUP BY state, state_desc, file_type, file_type_desc  
ORDER BY state, file_type  
state_descstate_desc file_type_descfile_type_desc countcount Размер на диске в МБon-disk size MB
PRECREATEDPRECREATED DATADATA 1616 20482048
PRECREATEDPRECREATED DELTADELTA 1616 128128
UNDER CONSTRUCTIONUNDER CONSTRUCTION DATADATA 22 268268
UNDER CONSTRUCTIONUNDER CONSTRUCTION DELTADELTA 22 1616
ACTIVEACTIVE DATADATA 4141 56085608
ACTIVEACTIVE DELTADELTA 4141 328328

В этом случае будет две пары файлов контрольных точек в состоянии "в разработке", а это означает, что несколько пар файлов были перемещены в состояние "в разработке", вероятнее всего, из-за высокого уровня параллелизма в рабочей нагрузке.In this case, there are two checkpoint file pairs in the 'under construction' state, which means multiple file pairs were moved to the 'under construction' state, likely due to the high level of concurrency in the workload. Нескольким параллельным потокам одновременно потребовалась новая пара файлов, из-за чего пара была переведена из состояния "создана заранее" в состояние "в разработке".Multiple concurrent threads required a new file pair at the same time, and thus moved a pair from 'precreated' to 'under construction'.

См. также:See Also

Выполняющаяся в памяти OLTP (оптимизация в памяти)In-Memory OLTP (In-Memory Optimization)