メモリ最適化テーブルをパーティション分割するためのアプリケーション パターン

適用対象:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

In-Memory OLTP では、現在のデータのパフォーマンスに優先順位を付けるアプリケーション設計パターンがサポートされています。 このパターンは、現在のデータの読み取りまたは更新の頻度が古いデータよりも大幅に多い場合に適用されます。 現在のデータは アクティブ または ホットと見なされ、古いデータは コールドです。

基本的には、"ホット" データをメモリ最適化テーブルに格納します。 週単位または月単位で、 コールド になる古いデータはパーティション テーブルに移動されます。 パーティション テーブルのデータは、メモリ内ではなく、ディスクまたは他のハード ドライブに格納されています。

通常、この設計では datetime2 キーを使用して、移動プロセスでホット データとコールド データを効率的に区別できるようにします。

高度なパーティション分割

この設計は、1 つのメモリ最適化パーティションも含むパーティション テーブルを模倣することを意図しています。 この設計を機能させるには、テーブルが共通のスキーマを共有していることを確認します。 この記事の後半にあるコード サンプルでは、この手法を示します。

新しいデータは常にホットと見なされます。 ホット データは、メモリ最適化テーブルに挿入され、更新されます。 コールド データは、従来のパーティション テーブルに保持されます。 ストアド プロシージャでは、定期的に新しいパーティションを追加します。 パーティションには、メモリ最適化テーブルから移動された最新のコールド データが含まれています。

操作でホット データのみが必要な場合は、ネイティブ コンパイル ストアド プロシージャを使用してデータにアクセスできます。 ホットまたはコールド データにアクセスする可能性がある操作では、解釈された Transact-SQL を使用して、メモリ最適化テーブルをパーティション テーブルと結合する必要があります。

パーティションを追加する

最近コールドになったデータは、パーティション テーブルに移動する必要があります。 この定期パーティション スワップの手順は次のとおりです。

  1. メモリ最適化テーブルのデータでは、ホット データと新しいコールド データの間の境界またはカットオフである datetime を決定します。

  2. In-Memory OLTP テーブルから新しくコールド データを cold_staging テーブルに挿入します。

  3. メモリ最適化テーブルから同じコールド データを削除します。

  4. cold_staging テーブルをパーティションにスワップします。

  5. パーティションを追加します。

メンテナンス期間

上記の手順の 1 つは、メモリ最適化テーブルから新しいコールド データを削除することです。 この削除と、新しいパーティションを追加する最後の手順の間には、時間間隔があります。 この間、新しくコールド データを読み取ろうとするすべてのアプリケーションが失敗します。

関連サンプルについては、「 アプリケーション レベルのパーティション分割」を参照してください。

コード サンプル

次の Transact-SQL サンプルは、プレゼンテーションを容易にする目的でのみ、一連の小さなコード ブロックで表示されています。 テストのために、それらをすべて 1 つの大きなコード ブロックに追加することができます。

全体として、T-SQL サンプルでは、メモリ最適化テーブルをディスク ベースのパーティション テーブルと共に使用する方法が示されています。

T-SQL サンプルの最初のフェーズでは、データベースを作成してから、データベース内にテーブルなどのオブジェクトを作成します。 後のフェーズでは、メモリ最適化テーブルからパーティション テーブルにデータを移動する方法を示します。

データベースの作成

T-SQL サンプルのこのセクションでは、テスト データベースを作成します。 データベースは、メモリ最適化テーブルとパーティション テーブルの両方をサポートするように構成されています。

CREATE DATABASE PartitionSample;
GO

-- Add a FileGroup, enabled for In-Memory OLTP.
-- Change file path as needed.
ALTER DATABASE PartitionSample
    ADD FILEGROUP PartitionSample_mod
    CONTAINS MEMORY_OPTIMIZED_DATA;

ALTER DATABASE PartitionSample
    ADD FILE (
        NAME = 'PartitionSample_mod',
        FILENAME = 'C:\data\PartitionSample_mod')
    TO FILEGROUP PartitionSample_mod;
GO

ホット データ用のメモリ最適化テーブルを作成する

このセクションでは、最新のデータ (ほとんどの場合、ホット データのままである) を保持するメモリ最適化テーブルを作成します。

USE PartitionSample;
GO

-- Create a memory-optimized table for the HOT Sales Order data.
-- Notice the index that uses DATETIME2.
CREATE TABLE dbo.SalesOrders_hot
(
    so_id INT IDENTITY PRIMARY KEY NONCLUSTERED,
    cust_id INT NOT NULL,
    so_date DATETIME2 NOT NULL INDEX ix_date NONCLUSTERED,
    so_total MONEY NOT NULL,
    INDEX ix_date_total NONCLUSTERED (so_date DESC, so_total DESC)
)
WITH (MEMORY_OPTIMIZED = ON);
GO

コールド データ用のパーティション テーブルを作成する

このセクションでは、コールド データを保持するパーティション テーブルを作成します。

-- Create a partition and table for the COLD Sales Order data.
-- Notice the index that uses DATETIME2.
CREATE PARTITION FUNCTION [ByDatePF](DATETIME2)
    AS RANGE RIGHT
    FOR VALUES ();
GO

CREATE PARTITION SCHEME [ByDateRange]
    AS PARTITION [ByDatePF]
    ALL TO ([PRIMARY]);
GO

CREATE TABLE dbo.SalesOrders_cold
(
    so_id INT NOT NULL,
    cust_id INT NOT NULL,
    so_date DATETIME2 NOT NULL,
    so_total MONEY NOT NULL,
    CONSTRAINT PK_SalesOrders_cold PRIMARY KEY (so_id, so_date),
    INDEX ix_date_total NONCLUSTERED (so_date DESC, so_total DESC)
) ON [ByDateRange](so_date);
GO

移動中にコールド データを格納するテーブルを作成する

このセクションでは、 cold_staging テーブルを作成します。 2 つのテーブルのホットおよびコールド データを結合するビューも作成されます。

-- A table used to briefly stage the newly cold data, during moves to a partition.
CREATE TABLE dbo.SalesOrders_cold_staging
(
    so_id INT NOT NULL,
    cust_id INT NOT NULL,
    so_date DATETIME2 NOT NULL,
    so_total MONEY NOT NULL,
    CONSTRAINT PK_SalesOrders_cold_staging PRIMARY KEY (so_id, so_date),
    CONSTRAINT CHK_SalesOrders_cold_staging CHECK (so_date >= '1900-01-01'),
    INDEX ix_date_total NONCLUSTERED (so_date DESC, so_total DESC)
);
GO

-- A view, for retrieving the aggregation of hot plus cold data.
CREATE VIEW dbo.SalesOrders AS
    SELECT so_id,
           cust_id,
           so_date,
           so_total,
           1 AS 'is_hot'
    FROM dbo.SalesOrders_hot
    UNION ALL
    SELECT so_id,
           cust_id,
           so_date,
           so_total,
           0 AS 'is_cold'
    FROM dbo.SalesOrders_cold;
GO

ストアド プロシージャを作成する

このセクションでは、定期的に実行するストアド プロシージャを作成します。 プロシージャでは、新しいコールド データをメモリ最適化テーブルからパーティション テーブルに移動します。

Note

このプロシージャを連続して呼び出すと、 SYSDATETIME() は連続する呼び出しで同じ datetime2 値を返す可能性があります。 その場合、境界値は既にパーティション関数に存在するため、エラー 7721 で ALTER PARTITION FUNCTION ... SPLIT RANGE が失敗します。 プロシージャの呼び出しをスペースアウトして、 @splitdate 値が呼び出しごとに異なるようにします。

-- A stored procedure to move all newly cold sales orders data
-- to its staging location.
CREATE PROCEDURE dbo.usp_SalesOrdersOffloadToCold
@splitdate DATETIME2
AS
BEGIN
    BEGIN TRANSACTION;

    -- Insert the cold data as a temporary heap.
    INSERT INTO dbo.SalesOrders_cold_staging WITH (TABLOCKX)
    SELECT so_id,
           cust_id,
           so_date,
           so_total
    FROM dbo.SalesOrders_hot WITH (SERIALIZABLE)
    WHERE so_date < @splitdate;

    -- Delete the moved data from the hot table.
    DELETE dbo.SalesOrders_hot WITH (SERIALIZABLE)
    WHERE so_date < @splitdate;

    -- Update the partition function, and switch in the new partition.
    ALTER PARTITION SCHEME [ByDateRange] NEXT USED [PRIMARY];

    DECLARE @p AS INT = (SELECT MAX(partition_number)
                         FROM sys.partitions
                         WHERE object_id = OBJECT_ID('dbo.SalesOrders_cold'));

    EXECUTE sp_executesql N'ALTER TABLE dbo.SalesOrders_cold_staging
            SWITCH TO dbo.SalesOrders_cold partition @i', N'@i int', @i = @p;

    ALTER PARTITION FUNCTION [ByDatePF]()
        SPLIT RANGE (@splitdate);

    -- Modify a constraint on the cold_staging table, to align with new partition.
    ALTER TABLE dbo.SalesOrders_cold_staging
    DROP CONSTRAINT CHK_SalesOrders_cold_staging;

    DECLARE @s AS NVARCHAR (100) = CONVERT (NVARCHAR (100), @splitdate, 121);

    DECLARE @sql AS NVARCHAR (1000) = N'ALTER TABLE dbo.SalesOrders_cold_staging
        ADD CONSTRAINT CHK_SalesOrders_cold_staging CHECK (so_date >= ''' + @s + ''')';

    PRINT @sql;

    EXECUTE sp_executesql @sql;

    COMMIT TRANSACTION;

END
GO

サンプル データを準備し、ストアド プロシージャのデモを行う

このセクションでは、サンプル データを生成して挿入してから、デモとしてストアド プロシージャを実行します。

-- Insert sample values into the hot table.
INSERT INTO dbo.SalesOrders_hot
VALUES (1, SYSDATETIME(), 1);
GO

INSERT INTO dbo.SalesOrders_hot
VALUES (1, SYSDATETIME(), 1);
GO

INSERT INTO dbo.SalesOrders_hot
VALUES (1, SYSDATETIME(), 1);
GO

-- Verify that the hot data is in the table, by selecting from the view.
SELECT *
FROM dbo.SalesOrders;
GO

-- Treat all data in the hot table as cold data:
-- Run the stored procedure, to move (offload) all sales orders to date to cold storage.
DECLARE @t AS DATETIME2 = SYSDATETIME();
EXECUTE dbo.usp_SalesOrdersOffloadToCold @t;

-- Again, read hot plus cold data from the view.
SELECT *
FROM dbo.SalesOrders;
GO

-- Retrieve the name of every partition.
SELECT OBJECT_NAME(object_id),
       *
FROM sys.dm_db_partition_stats AS ps
WHERE object_id = OBJECT_ID('dbo.SalesOrders_cold');

-- Insert more data into the hot table.
INSERT INTO dbo.SalesOrders_hot
VALUES (2, SYSDATETIME(), 1);
GO

INSERT INTO dbo.SalesOrders_hot
VALUES (2, SYSDATETIME(), 1);
GO

INSERT INTO dbo.SalesOrders_hot
VALUES (2, SYSDATETIME(), 1);
GO

-- Read hot plus cold data from the view.
SELECT *
FROM dbo.SalesOrders;
GO

-- Again, run the stored procedure, to move all sales orders to date to cold storage.
DECLARE @t AS DATETIME2 = SYSDATETIME();
EXECUTE dbo.usp_SalesOrdersOffloadToCold @t;

-- Read hot plus cold data from the view.
SELECT *
FROM dbo.SalesOrders;
GO

-- Again, retrieve the name of every partition.
-- The stored procedure can modify the partitions.
SELECT OBJECT_NAME(object_id),
       partition_number,
       row_count
FROM sys.dm_db_partition_stats AS ps
WHERE object_id = OBJECT_ID('dbo.SalesOrders_cold')
      AND index_id = 1;

すべてのデモ オブジェクトを削除する

テスト システムからデモ テスト データベースを消去することを忘れないでください。

USE master;
GO

DROP DATABASE PartitionSample;
GO