次の方法で共有


Synapse SQL の統計

この記事では、Synapse SQL リソース (専用 SQL プールとサーバーレス SQL プール) を使用してクエリ最適化統計を作成および更新するための推奨事項と例を示します。

専用 SQL プールの統計

統計を使用する理由

専用 SQL プールがデータを認識するほど、クエリの実行速度が速くなります。 専用 SQL プールにデータを読み込んだ後、データに関する統計を収集することは、クエリの最適化のために実行できる最も重要なことの 1 つです。

専用 SQL プール クエリ オプティマイザーは、コストベースのオプティマイザーです。 オプティマイザーでは、さまざまなクエリ プランのコストが比較されて、最も低コストのプランが選択されます。 ほとんどの場合、最も高速に実行されるプランが選択されます。

たとえば、クエリがフィルター処理されている日付が 1 行返されるとオプティマイザーが見積もった場合、1 つのプランが選択されます。 選択した日付が 100 万行を返すと推定された場合は、別のプランが返されます。

統計の自動作成

専用 SQL プール エンジンは、データベース AUTO_CREATE_STATISTICS オプションが ON に設定されている場合、入力ユーザー クエリで不足している統計を分析します。 統計が足りない場合、クエリ オプティマイザーでは、クエリ述語または結合条件内の個々の列で統計を作成します。

この関数は、クエリ プランのカーディナリティの見積もりを向上させるために使用されます。

重要

既定では、統計の自動作成は有効です。

データ ウェアハウスで AUTO_CREATE_STATISTICS が構成されているかどうかは、次のコマンドを実行することで確認できます。

SELECT name, is_auto_create_stats_on
FROM sys.databases

データ ウェアハウスでAUTO_CREATE_STATISTICSが有効になっていない場合は、次のコマンドを実行してこのプロパティを有効にすることをお勧めします。

ALTER DATABASE <yourdatawarehousename>
SET AUTO_CREATE_STATISTICS ON

これらのステートメントにより、統計の自動作成がトリガーされます。

  • 選択する
  • INSERT-SELECT
  • CTAS
  • 更新
  • 削除
  • EXPLAIN (結合を含む場合や述語の存在が検出された場合)

統計の自動作成は、一時テーブルまたは外部テーブルでは生成されません。

統計の自動作成は同期的に行われます。 そのため、列に統計がない場合は、クエリのパフォーマンスが若干低下する可能性があります。 1 つの列の統計を作成する時間は、テーブルのサイズに依存します。

明らかなパフォーマンスの低下を回避するには、システムをプロファイルする前にベンチマーク用ワークロードを実行することによって、統計を先に作成しておく必要があります。

統計の作成は、各ユーザー コンテキスト内の sys.dm_pdw_exec_requests にログ記録されます。

自動統計が作成されると、形式はWA_Sys<8 桁の列 ID(16 進数で)>_<8 桁のテーブル ID(16 進数で)>となります。 DBCC SHOW_STATISTICS コマンドを実行すると、既に作成された統計を表示できます。

DBCC SHOW_STATISTICS (<table_name>, <target>)

table_nameは、表示する統計を含むテーブルの名前です。外部テーブルにすることはできません。 target は、統計情報を表示するターゲットのインデックス、統計、または列の名前です。

統計を更新します。

ベスト プラクティスの 1 つが、新しい日付が追加されるたびに日付列の統計を更新することです。 新しい行がデータ ウェアハウスに読み込まれるたびに、新しい読み込み日またはトランザクションの日付が追加されます。 これらの追加によってデータの分布が変わり、統計が古くなります。

値の分布は通常変更されないため、顧客テーブルの国または地域の列の統計を更新する必要がない場合があります。 顧客間で分布が一定であると仮定すると、テーブル バリエーションに新しい行を追加しても、データの分布が変わることはありません。

ただし、データ ウェアハウスに含まれる国または地域が 1 つだけで、新しい国または地域からデータを取り込む場合は、国または地域の列の統計を更新する必要があります。

統計更新のレコメンデーションは次のとおりです。

タイプ 勧告
統計の更新の頻度 控え目: 毎日
データの読み込みまたは変換後
サンプリング 行数が 10 億未満の場合は、既定のサンプリング (20%) が使用されます。
10 億行を超えると、2% のサンプリングが使用されます。

統計の最後の更新を決定する

クエリのトラブルシューティングを行うときに最初に質問する質問の 1 つは、 "統計は最新ですか?

この質問は、データの経過時間によって回答できる質問ではありません。 基になるデータに重要な変更がない場合は、最新の統計オブジェクトが古い可能性があります。 行数が大幅に変更された場合、または列の値の分布に大きな変化が生じた 場合 は、統計を更新します。

前回統計が更新されてからテーブル内のデータが変更されたかどうかを判断するための動的管理ビューはありません。 統計の年齢を知ることで、画像の一部を得ることができます。

次のクエリを使用して、各テーブルで統計が最後に更新された時刻を確認できます。

列の値の分布に重大な変更がある場合は、最後に更新された時刻に関係なく統計を更新する必要があります。

SELECT
    sm.[name] AS [schema_name],
    tb.[name] AS [table_name],
    co.[name] AS [stats_column_name],
    st.[name] AS [stats_name],
    STATS_DATE(st.[object_id],st.[stats_id]) AS [stats_last_updated_date]
FROM
    sys.objects ob
    JOIN sys.stats st
        ON  ob.[object_id] = st.[object_id]
    JOIN sys.stats_columns sc
        ON  st.[stats_id] = sc.[stats_id]
        AND st.[object_id] = sc.[object_id]
    JOIN sys.columns co
        ON  sc.[column_id] = co.[column_id]
        AND sc.[object_id] = co.[object_id]
    JOIN sys.types  ty
        ON  co.[user_type_id] = ty.[user_type_id]
    JOIN sys.tables tb
        ON  co.[object_id] = tb.[object_id]
    JOIN sys.schemas sm
        ON  tb.[schema_id] = sm.[schema_id]
WHERE
    st.[user_created] = 1;

たとえば、データ ウェアハウスの日付列には、通常、頻繁に統計を更新する必要があります。 新しい行がデータ ウェアハウスに読み込まれるたびに、新しい読み込み日またはトランザクションの日付が追加されます。 これらの追加によってデータの分布が変わり、統計が古くなります。

顧客テーブルの性別列の統計を更新する必要がない場合があります。 顧客間で分布が一定であると仮定すると、テーブル バリエーションに新しい行を追加しても、データの分布が変わることはありません。

ただし、データ ウェアハウスに含まれる性別が 1 つだけで、新しい要件によって複数の性別が生じる場合は、性別列の統計を更新する必要があります。

詳細については、 統計 に関する記事を参照してください。

統計管理の実装

多くの場合、読み込みの終わりに統計が確実に更新されるように、データ読み込みプロセスを拡張することが推奨されます。 テーブルのサイズと値の分布のどちらかまたは両方が変わる頻度が最も高いのがデータの読み込み時です。 そのため、読み込みプロセスは、管理プロセスを実装する論理的な場所となります。

読み込みプロセスで統計を更新する際の基本原則は、次のとおりです。

  • 読み込まれた各テーブルに更新された統計オブジェクトが少なくとも 1 つは含まれていることを確認します。 このプロセスにより、統計の更新の一環として、テーブル サイズ (行数とページ数) 情報が更新されます。
  • JOIN、GROUP BY、ORDER BY、DISTINCT の各句に関与している列を重視します。
  • トランザクションの日付などの "昇順キー" 列の値は、統計ヒストグラムに含まれないため、これらの列の更新頻度を増やすことを検討します。
  • 静的な分布列の更新頻度を減らすことを検討します。
  • 各統計オブジェクトは順序どおりに更新されることに注意してください。 特に、多数の統計オブジェクトが含まれた幅の広いテーブルでは、 UPDATE STATISTICS <TABLE_NAME> を実装するだけでは十分とはいえない場合があります。

詳細については、「 カーディナリティ推定」を参照してください。

例 :統計を作成する

以下の例では、さまざまなオプションを使用して統計を作成する方法を示します。 各列に使用するオプションは、データの特性と、クエリでの列の使用方法によって異なります。

既定のオプションを使用した単一列統計の作成

列の統計を作成するには、統計オブジェクトの名前と列の名前を指定します。 次の構文では、既定のオプションをすべて使用しています。 既定では、専用 SQL プールは統計を作成するときにテーブルの 20% をサンプリングします。

CREATE STATISTICS [statistics_name]
    ON [schema_name].[table_name]([column_name]);

例えば次が挙げられます。

CREATE STATISTICS col1_stats
    ON dbo.table1 (col1);

すべての列の検査による単一列統計の作成

ほとんどの場合、20% という既定のサンプリング レートで十分です。 ただし、サンプリング レートを調整することもできます。 テーブル全体をサンプリングするには、次の構文を使用します。

CREATE STATISTICS [statistics_name]
    ON [schema_name].[table_name]([column_name])
    WITH FULLSCAN;

例えば次が挙げられます。

CREATE STATISTICS col1_stats
    ON dbo.table1 (col1)
    WITH FULLSCAN;

サンプル サイズを指定した単一列統計の作成

もう 1 つのオプションは、サンプル サイズをパーセントで指定することです。

CREATE STATISTICS col1_stats
    ON dbo.table1 (col1)
    WITH SAMPLE 50 PERCENT;

一部の行のみの単一列統計の作成

テーブル内の行の一部を対象としたフィルタリングされた統計を作成することもできます。

たとえば、大規模なパーティション テーブルの特定のパーティションのクエリを計画するときに、フィルター選択された統計を使用できます。 パーティション値のみに統計を作成することで、統計の精度が向上します。 クエリのパフォーマンスも向上します。

次の例では、値の範囲の統計を作成します。 パーティションの値の範囲に一致する値を簡単に定義できます。

CREATE STATISTICS stats_col1
    ON table1(col1)
    WHERE col1 > '2000101' AND col1 < '20001231';

クエリ オプティマイザーが分散クエリ プランを選択するときに、フィルター選択された統計の使用も考慮されるようにするには、クエリが統計オブジェクトの定義の範囲内である必要があります。 前の例では、クエリの WHERE 句で col1 の値として 2000101 ~ 20001231 の値を指定する必要があります。

すべてのオプションを使用した単一列統計の作成

オプションは組み合わせることができます。 次の例では、カスタム サンプル サイズを指定してフィルター選択された統計オブジェクトを作成します。

CREATE STATISTICS stats_col1
    ON table1 (col1)
    WHERE col1 > '2000101' AND col1 < '20001231'
    WITH SAMPLE 50 PERCENT;

詳細については、「CREATE STATISTICS」をご覧ください。

複数列統計の作成

複数列統計オブジェクトを作成するには、これまでの例を使用しますが、複数の列を指定します。

クエリ結果の行数の推定に使用されるヒストグラムは、統計オブジェクト定義に示されている最初の列にのみ使用できます。

この例では、ヒストグラムは product_category上にあります。 クロス列統計は、 product_categoryproduct_sub_categoryで計算されます。

CREATE STATISTICS stats_2cols
    ON table1 (product_category, product_sub_category)
    WHERE product_category > '2000101' AND product_category < '20001231'
    WITH SAMPLE 50 PERCENT;

product_categoryproduct_sub_categoryの間には相関関係があるため、複数列の統計オブジェクトは、これらの列に同時にアクセスする場合に便利です。 このテーブルのクエリを実行すると、複数列の統計によって、結合、GROUP BY 集計、個別のカウント、WHERE フィルターのカーディナリティ推定が向上します (プライマリ統計列がフィルターの一部である限り)。

テーブルのすべての列の統計の作成

統計を作成する方法の 1 つは、テーブルの作成後に CREATE STATISTICS コマンドを発行することです。

CREATE TABLE dbo.table1
(
   col1 int
,  col2 int
,  col3 int
)
WITH
  (
    CLUSTERED COLUMNSTORE INDEX
  )
;

CREATE STATISTICS stats_col1 on dbo.table1 (col1);
CREATE STATISTICS stats_col2 on dbo.table2 (col2);
CREATE STATISTICS stats_col3 on dbo.table3 (col3);

ストアド プロシージャを使用して、データベース内のすべての列の統計を作成する

SQL プールには、SQL Server の sp_create_stats と同等のシステム ストアド プロシージャがありません。 このストアド プロシージャは、統計がまだないデータベースのすべての列に対して、1 つの列統計オブジェクトを作成します。

次の例は、データベース設計の開始に役立ちます。 お客様のニーズに合わせて自由に調整してください。

CREATE PROCEDURE    [dbo].[prc_sqldw_create_stats]
(   @create_type    tinyint -- 1 default, 2 Fullscan, 3 Sample
,   @sample_pct     tinyint
)
AS

IF @create_type IS NULL
BEGIN
    SET @create_type = 1;
END;

IF @create_type NOT IN (1,2,3)
BEGIN
    THROW 151000,'Invalid value for @stats_type parameter. Valid range 1 (default), 2 (fullscan) or 3 (sample).',1;
END;

IF @sample_pct IS NULL
BEGIN;
    SET @sample_pct = 20;
END;

IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN;
    DROP TABLE #stats_ddl;
END;

CREATE TABLE #stats_ddl
WITH    (   DISTRIBUTION    = HASH([seq_nmbr])
        ,   LOCATION        = USER_DB
        )
AS
WITH T
AS
(
SELECT      t.[name]                        AS [table_name]
,           s.[name]                        AS [table_schema_name]
,           c.[name]                        AS [column_name]
,           c.[column_id]                   AS [column_id]
,           t.[object_id]                   AS [object_id]
,           ROW_NUMBER()
            OVER(ORDER BY (SELECT NULL))    AS [seq_nmbr]
FROM        sys.[tables] t
JOIN        sys.[schemas] s         ON  t.[schema_id]       = s.[schema_id]
JOIN        sys.[columns] c         ON  t.[object_id]       = c.[object_id]
LEFT JOIN   sys.[stats_columns] l   ON  l.[object_id]       = c.[object_id]
                                    AND l.[column_id]       = c.[column_id]
                                    AND l.[stats_column_id] = 1
LEFT JOIN    sys.[external_tables] e    ON    e.[object_id]        = t.[object_id]
WHERE       l.[object_id] IS NULL
AND            e.[object_id] IS NULL -- not an external table
)
SELECT  [table_schema_name]
,       [table_name]
,       [column_name]
,       [column_id]
,       [object_id]
,       [seq_nmbr]
,       CASE @create_type
        WHEN 1
        THEN    CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+')' AS VARCHAR(8000))
        WHEN 2
        THEN    CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+') WITH FULLSCAN' AS VARCHAR(8000))
        WHEN 3
        THEN    CAST('CREATE STATISTICS '+QUOTENAME('stat_'+table_schema_name+ '_' + table_name + '_'+column_name)+' ON '+QUOTENAME(table_schema_name)+'.'+QUOTENAME(table_name)+'('+QUOTENAME(column_name)+') WITH SAMPLE '+CONVERT(varchar(4),@sample_pct)+' PERCENT' AS VARCHAR(8000))
        END AS create_stat_ddl
FROM T
;

DECLARE @i INT              = 1
,       @t INT              = (SELECT COUNT(*) FROM #stats_ddl)
,       @s NVARCHAR(4000)   = N''
;

WHILE @i <= @t
BEGIN
    SET @s=(SELECT create_stat_ddl FROM #stats_ddl WHERE seq_nmbr = @i);

    PRINT @s
    EXEC sp_executesql @s
    SET @i+=1;
END

DROP TABLE #stats_ddl;

既定値を使用してテーブルのすべての列の統計を作成するには、ストアド プロシージャを実行します。

EXEC [dbo].[prc_sqldw_create_stats] 1, NULL;

fullscan を使用してテーブル内のすべての列の統計を作成するには、次の手順を呼び出します。

EXEC [dbo].[prc_sqldw_create_stats] 2, NULL;

テーブル内のすべての列に対してサンプリングされた統計を作成するには、「3」と入力し、サンプルの割合を入力します。 次の手順では、20% のサンプル レートを使用します。

EXEC [dbo].[prc_sqldw_create_stats] 3, 20;

例 :統計を更新します。

統計を更新するには、次の操作を行います。

  • 統計オブジェクトを 1 つ更新します。 更新する統計オブジェクトの名前を指定します。
  • テーブルのすべての統計オブジェクトを更新します。 特定の統計オブジェクトではなく、テーブルの名前を指定します。

1 つの特定の統計オブジェクトの更新

特定の統計オブジェクトを更新するには、次の構文を使用します。

UPDATE STATISTICS [schema_name].[table_name]([stat_name]);

例えば次が挙げられます。

UPDATE STATISTICS [dbo].[table1] ([stats_col1]);

特定の統計オブジェクトを更新することで、統計を管理するために必要な時間とリソースを最小限に抑えることができます。 このアクションでは、更新する最適な統計オブジェクトを選択するためのいくつかの考慮事項が必要です。

テーブルのすべての統計を更新する

テーブルのすべての統計オブジェクトを更新する簡単な方法を次に示します。

UPDATE STATISTICS [schema_name].[table_name];

例えば次が挙げられます。

UPDATE STATISTICS dbo.table1;

UPDATE STATISTICS ステートメントは簡単に使用できます。 テーブル のすべての 統計が更新され、必要以上の作業が求められることに注意してください。

パフォーマンスが問題でない場合は、統計が最新であることを保証する最も簡単で最も完全な方法です。

テーブルのすべての統計を更新する場合、専用 SQL プールはスキャンを実行して、各統計オブジェクトのテーブルをサンプリングします。 テーブルが大きく、多数の列と統計が含まれている場合は、ニーズに基づいて個々の統計を更新する方が効率的です。

UPDATE STATISTICSプロシージャの実装については、一時テーブルを参照してください。 実装方法は前述の CREATE STATISTICS プロシージャと若干異なりますが、結果は同じです。 完全な構文については、「 統計の更新」を参照してください。

統計のメタデータ

統計に関する情報を確認する際に使用できるシステム ビューとシステム関数がいくつかあります。 たとえば、STATS_DATE() 関数を使用すると、統計オブジェクトが古くなっている可能性があるかどうかを確認できます。 STATS_DATE() を使用すると、統計が最後に作成または更新された日時を確認できます。

統計のカタログ ビュー

次のシステム ビューは、統計に関する情報を提供します。

カタログ ビュー 説明
sys.columns 列ごとに 1 行。
sys.objects データベース内のオブジェクトごとに 1 行。
sys.schemas データベース内のスキーマごとに 1 行。
sys.stats 統計オブジェクトごとに 1 行。
sys.stats_columns 統計オブジェクト内の列ごとに 1 行。 sys.columns にリンク。
sys.tables テーブルごとに 1 行 (外部テーブルを含む)。
sys.table_types データ型ごとに 1 行。

統計のシステム関数

次のシステム関数は統計の操作に役立ちます。

システム関数 説明
STATS_DATE 統計オブジェクトが最後に更新された日付。
DBCC SHOW_STATISTICS 統計オブジェクトによって認識される値の分布に関する概要レベルと詳細情報。

1 つのビューへの統計列と関数の統合

このビューでは、STATS_DATE() 関数の統計と結果に関連する列が一緒に表示されます。

CREATE VIEW dbo.vstats_columns
AS
SELECT
        sm.[name]                           AS [schema_name]
,       tb.[name]                           AS [table_name]
,       st.[name]                           AS [stats_name]
,       st.[filter_definition]              AS [stats_filter_definition]
,       st.[has_filter]                     AS [stats_is_filtered]
,       STATS_DATE(st.[object_id],st.[stats_id])
                                            AS [stats_last_updated_date]
,       co.[name]                           AS [stats_column_name]
,       ty.[name]                           AS [column_type]
,       co.[max_length]                     AS [column_max_length]
,       co.[precision]                      AS [column_precision]
,       co.[scale]                          AS [column_scale]
,       co.[is_nullable]                    AS [column_is_nullable]
,       co.[collation_name]                 AS [column_collation_name]
,       QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
                                            AS two_part_name
,       QUOTENAME(DB_NAME())+'.'+QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
                                            AS three_part_name
FROM    sys.objects                         AS ob
JOIN    sys.stats           AS st ON    ob.[object_id]      = st.[object_id]
JOIN    sys.stats_columns   AS sc ON    st.[stats_id]       = sc.[stats_id]
                            AND         st.[object_id]      = sc.[object_id]
JOIN    sys.columns         AS co ON    sc.[column_id]      = co.[column_id]
                            AND         sc.[object_id]      = co.[object_id]
JOIN    sys.types           AS ty ON    co.[user_type_id]   = ty.[user_type_id]
JOIN    sys.tables          AS tb ON    co.[object_id]      = tb.[object_id]
JOIN    sys.schemas         AS sm ON    tb.[schema_id]      = sm.[schema_id]
WHERE   1=1
AND     st.[user_created] = 1
;

DBCC SHOW_STATISTICS() の例

DBCC SHOW_STATISTICS() には、統計オブジェクト内に保持されているデータが表示されます。 このデータは 3 つの部分で提供されます。

  • ヘッダ
  • 密度ベクトル
  • ヒストグラム

ヘッダーは、統計に関するメタデータです。 ヒストグラムには、統計オブジェクトの最初のキー列の値の分布が表示されます。

密度ベクトルは、列間の相関関係を測定します。 専用 SQL プールでは、統計オブジェクト内のデータを使用してカーディナリティ推定値を計算します。

ヘッダー、密度、ヒストグラムの表示

次の簡単な例は、統計オブジェクトの 3 つの部分をすべて表示します。

DBCC SHOW_STATISTICS([<schema_name>.<table_name>],<stats_name>)

例えば次が挙げられます。

DBCC SHOW_STATISTICS ('dbo.table1', 'stats_col1');

DBCC SHOW_STATISTICS() の 1 つ以上の部分の表示

特定の部分だけを表示する場合は、WITH 句を使用して表示する部分を指定します。

DBCC SHOW_STATISTICS([<schema_name>.<table_name>],<stats_name>)
    WITH stat_header, histogram, density_vector

例えば次が挙げられます。

DBCC SHOW_STATISTICS ('dbo.table1', 'stats_col1')
    WITH histogram, density_vector

DBCC SHOW_STATISTICS() の相違点

SQL Server に比べ、専用 SQL プールには、DBCC SHOW_STATISTICS() がより厳密に実装されています。

  • ドキュメントに記載されていない機能はサポートされていません。
  • Stats_streamを使用できません。
  • 統計データの特定のサブセットの結果を結合することはできません。 たとえば、STAT_HEADER JOIN DENSITY_VECTOR。
  • NO_INFOMSGSはメッセージ抑制に設定できません。
  • 統計名を囲む角かっこは使用できません。
  • 列名を使用して、統計オブジェクトを識別することはできません。
  • カスタム エラー 2767 はサポートされていません。

サーバーレス SQL プールの統計

統計は、特定のデータセット (ストレージ パス) の特定の列ごとに作成されます。

LOB 列の統計を作成できません。

統計を使用する理由

サーバーレス SQL プールがデータについて認識するほど、データに対するクエリの実行速度が速くなります。 データに関する統計を収集することは、クエリを最適化するために実行できる最も重要なことの 1 つです。

サーバーレス SQL プール クエリ オプティマイザーは、コストベースのオプティマイザーです。 オプティマイザーでは、さまざまなクエリ プランのコストが比較されて、最も低コストのプランが選択されます。 ほとんどの場合、最も高速に実行されるプランが選択されます。

たとえば、クエリがフィルター処理されている日付が 1 行返されるとオプティマイザーが推定した場合、1 つのプランが選択されます。 選択した日付が 100 万行を返すと推定される場合は、別のプランが選択されます。

統計の自動作成

サーバーレス SQL プールは、受信ユーザー クエリで不足している統計を分析します。 統計が足りない場合、クエリ オプティマイザーでは、クエリ述語または結合条件内の個々の列で統計を作成することで、クエリ プランに対するカーディナリティ評価が改善されます。

SELECT ステートメントによって統計の自動作成がトリガーされます。

統計サンプリングの自動作成が使用され、ほとんどの場合、サンプリング率は 100%未満になります。 このフローは、すべてのファイル形式で同じです。 パーサー バージョン 1.0 のサンプリングを使用して CSV を読み取る場合はサポートされておらず、サンプリング率が 100%未満では統計の自動作成は行われません。 カーディナリティが低い (行数) と推定される小さなテーブルの場合、サンプリングの割合が 100% の自動統計作成がトリガーされます。 これは基本的に、パーサー バージョン 1.0 の CSV でも fullscan がトリガーされ、自動統計が作成されることを意味します。

統計の自動作成は同期的に行われるので、列に統計がない場合、クエリのパフォーマンスが若干低下する可能性があります。 1 つの列の統計を作成する時間は、ターゲットとされるファイルのサイズに依存します。

統計の手動作成

サーバーレス SQL プールを使用すると、統計を手動で作成できます。 CSV でパーサー バージョン 1.0 を使用している場合、このパーサー バージョンではサンプリングがサポートされていないため、統計を手動で作成する必要があります。 パーサー バージョン 1.0 の場合の統計の自動作成は、サンプリング率が 100%でない限り発生しません。

統計を手動で作成する方法については、次の例を参照してください。

統計を更新します。

ファイル内のデータの変更、ファイルの削除、追加により、データ分散が変更され、統計が古くなります。 その場合は、統計を更新する必要があります。

データが大幅に変更された場合、サーバーレス SQL プールは OPENROWSET 列の統計を自動的に再作成します。 統計が自動的に作成されるたびに、データセットの現在の状態 (ファイル パス、サイズ、最終変更日) も保存されます。

統計が古い場合は、新しい統計が作成されます。 アルゴリズムはデータを通過し、データセットの現在の状態と比較します。 変更のサイズが特定のしきい値を超える場合は、古い統計が削除され、新しいデータセットに対して再作成されます。

手動統計は古いとは宣言されません。

統計サンプリングの自動再作成が使用され、ほとんどの場合、サンプリング率は 100%未満になります。 このフローは、すべてのファイル形式で同じです。 パーサー バージョン 1.0 のサンプリングを使用して CSV を読み取る場合はサポートされておらず、サンプリング率が 100%未満では統計の自動再作成は行われません。 その場合は、統計を手動で削除して再作成する必要があります。 統計を削除して作成する方法については、以下の例を参照してください。 カーディナリティ (行数) が低いと推定される小さなテーブルの場合、サンプリング率が 100% の自動統計の再作成がトリガーされます。 これは基本的に、パーサー バージョン 1.0 の CSV でも fullscan がトリガーされ、自動統計が作成されることを意味します。

クエリのトラブルシューティングを行うときに最初に質問する質問の 1 つは、 "統計は最新ですか?

行数が大幅に変わった場合や、列の値の分布で重大な変更があった場合は、"その後で" 統計を更新する必要があります。

列の値の分布に重大な変更がある場合は、最後に更新された時刻に関係なく統計を更新する必要があります。

統計管理の実装

データ パイプラインを拡張して、ファイルの追加、削除、または変更によってデータが大幅に変更されたときに統計が更新されるようにすることができます。

統計を更新する際の基本原則は、次のとおりです。

  • データセットに少なくとも 1 つの統計オブジェクトが更新されていることを確認します。 これにより、統計の更新の一環として、サイズ (行数とページ数) 情報が更新されます。
  • WHERE、JOIN、GROUP BY、ORDER BY、DISTINCT の各句に関与している列を重視します。
  • これらの値は統計ヒストグラムに含まれないため、トランザクションの日付などの "昇順キー" 列をより頻繁に更新します。
  • 静的分散列の更新頻度が低くなります。

詳細については、「 カーディナリティ推定」を参照してください。

例: OPENROWSET パスの列の統計を作成する

次の例では、Azure Synapse サーバーレス SQL プールで統計を作成するためのさまざまなオプションを使用する方法を示します。 各列に使用するオプションは、データの特性と、クエリでの列の使用方法によって異なります。 これらの例で使用されるストアド プロシージャの詳細については、サーバーレス SQL プールにのみ適用される sys.sp_create_openrowset_statisticssys.sp_drop_openrowset_statisticsを確認してください。

この時点でのみ、単一列の統計を作成できます。

sp_create_openrowset_statisticssp_drop_openrowset_statisticsを実行するには、次の権限が必要です: 一括操作の管理権限またはデータベースの一括操作の管理権限。

統計を作成するには、次のストアド プロシージャを使用します。

sys.sp_create_openrowset_statistics [ @stmt = ] N'statement_text'

引数: [ @stmt = ] N'statement_text' - 統計に使用する列値を返す Transact-SQL ステートメントを指定します。 TABLESAMPLE を使用して、使用するデータのサンプルを指定できます。 TABLESAMPLE が指定されていない場合は、FULLSCAN が使用されます。

<tablesample_clause> ::= TABLESAMPLE ( sample_number PERCENT )

パーサー バージョン 1.0 を使用している場合、CSV サンプリングは機能しません。パーサー バージョン 1.0 の CSV では FULLSCAN のみがサポートされます。

すべての列の検査による単一列統計の作成

列に統計を作成するには、統計が必要な列を返すクエリを指定します。

既定では、統計を手動で作成するときに別の方法を指定しない場合、サーバーレス SQL プールでは、統計の作成時にデータセットに指定されたデータの 100% が使用されます。

たとえば、us_population.csv ファイルに基づくデータセットの人口列について、既定のオプションである FULLSCAN を使用して統計を作成するには、次のようにします。


EXEC sys.sp_create_openrowset_statistics N'SELECT 
    population
FROM OPENROWSET(
    BULK ''https://azureopendatastorage.blob.core.windows.net/censusdatacontainer/raw_us_population_county/us_population.csv'',
    FORMAT = ''CSV'',
    PARSER_VERSION = ''2.0'',
    HEADER_ROW = TRUE)
AS [r]'

サンプル サイズを指定した単一列統計の作成

サンプル サイズはパーセントで指定できます。

/* make sure you have credentials for storage account access created
IF EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://azureopendatastorage.blob.core.windows.net/censusdatacontainer')
DROP CREDENTIAL [https://azureopendatastorage.blob.core.windows.net/censusdatacontainer]
GO

CREATE CREDENTIAL [https://azureopendatastorage.blob.core.windows.net/censusdatacontainer]  
WITH IDENTITY='SHARED ACCESS SIGNATURE',  
SECRET = ''
GO
*/

EXEC sys.sp_create_openrowset_statistics N'SELECT payment_type
FROM OPENROWSET(
        BULK ''https://sqlondemandstorage.blob.core.windows.net/parquet/taxi/year=2018/month=6/*.parquet'',
         FORMAT = ''PARQUET''
    ) AS [nyc]
    TABLESAMPLE(5 PERCENT)
'

例 :統計を更新します。

統計を更新するには、既存の統計を削除し、新たに作成する必要があります。 詳細については、 sys.sp_create_openrowset_statisticssys.sp_drop_openrowset_statisticsを確認してください。

sys.sp_drop_openrowset_statistics ストアド プロシージャは、統計を削除するために使用されます。

sys.sp_drop_openrowset_statistics [ @stmt = ] N'statement_text'

sp_create_openrowset_statisticssp_drop_openrowset_statisticsを実行するには、次の権限が必要です: 一括操作の管理権限またはデータベースの一括操作の管理権限。

引数: [ @stmt = ] N'statement_text' - 統計の作成時に使用されるのと同じ Transact-SQL ステートメントを指定します。

population.csv ファイルに基づいたデータセットの year 列の統計を更新するには、統計を削除して作成する必要があります。

EXEC sys.sp_drop_openrowset_statistics N'SELECT payment_type
FROM OPENROWSET(
        BULK ''https://sqlondemandstorage.blob.core.windows.net/parquet/taxi/year=2018/month=6/*.parquet'',
         FORMAT = ''PARQUET''
    ) AS [nyc]
    TABLESAMPLE(5 PERCENT)
'
GO

/* make sure you have credentials for storage account access created
IF EXISTS (SELECT * FROM sys.credentials WHERE name = 'https://azureopendatastorage.blob.core.windows.net/censusdatacontainer')
DROP CREDENTIAL [https://azureopendatastorage.blob.core.windows.net/censusdatacontainer]
GO

CREATE CREDENTIAL [https://azureopendatastorage.blob.core.windows.net/censusdatacontainer]  
WITH IDENTITY='SHARED ACCESS SIGNATURE',  
SECRET = ''
GO
*/

EXEC sys.sp_create_openrowset_statistics N'SELECT payment_type
FROM OPENROWSET(
        BULK ''https://sqlondemandstorage.blob.core.windows.net/parquet/taxi/year=2018/month=6/*.parquet'',
         FORMAT = ''PARQUET''
    ) AS [nyc]
    TABLESAMPLE(5 PERCENT)
'

例: 外部テーブル列の統計を作成する

次の例では、統計を作成するためにさまざまなオプションを使用する方法を示します。 各列に使用するオプションは、データの特性と、クエリでの列の使用方法によって異なります。

この時点でのみ、単一列の統計を作成できます。

列の統計を作成するには、統計オブジェクトの名前と列の名前を指定します。

CREATE STATISTICS statistics_name
ON { external_table } ( column )
    WITH
        { FULLSCAN
          | [ SAMPLE number PERCENT ] }
        , { NORECOMPUTE }

引数: external_table 統計を作成する外部テーブルを指定します。

FULLSCAN すべての行をスキャンして統計を計算します。 FULLSCAN と SAMPLE 100 PERCENT は同じ結果になります。 SAMPLE オプションには FULLSCAN を使用できません。

SAMPLE number PERCENT: クエリ オプティマイザーが統計を作成するときに使用するテーブルまたはインデックス付きビューのおおよその割合または行数を指定します。 数値は 0 ~ 100 です。

FULLSCAN オプションには SAMPLE を使用できません。

パーサー バージョン 1.0 を使用している場合、CSV サンプリングは機能しません。パーサー バージョン 1.0 の CSV では FULLSCAN のみがサポートされます。

すべての列の検査による単一列統計の作成

CREATE STATISTICS sState
    on census_external_table (STATENAME)
    WITH FULLSCAN, NORECOMPUTE

サンプル サイズを指定した単一列統計の作成

-- following sample creates statistics with sampling 5%
CREATE STATISTICS sState
    on census_external_table (STATENAME)
    WITH SAMPLE 5 percent, NORECOMPUTE

例 :統計を更新します。

統計を更新するには、既存の統計を削除し、新たに作成する必要があります。 最初に統計を削除します。

DROP STATISTICS census_external_table.sState

統計を作成します。

CREATE STATISTICS sState
    on census_external_table (STATENAME)
    WITH FULLSCAN, NORECOMPUTE

統計のメタデータ

統計に関する情報を確認する際に使用できるシステム ビューとシステム関数がいくつかあります。 たとえば、STATS_DATE() 関数を使用すると、統計オブジェクトが古くなっている可能性があるかどうかを確認できます。 STATS_DATE() を使用すると、統計が最後に作成または更新された日時を確認できます。

統計メタデータは、外部テーブル列でのみ使用できます。 OPENROWSET 列では統計メタデータを使用できません。

統計のカタログ ビュー

次のシステム ビューは、統計に関する情報を提供します。

カタログ ビュー 説明
sys.columns 列ごとに 1 行。
sys.objects データベース内のオブジェクトごとに 1 行。
sys.schemas データベース内のスキーマごとに 1 行。
sys.stats 統計オブジェクトごとに 1 行。
sys.stats_columns 統計オブジェクト内の列ごとに 1 行。 sys.columns にリンク。
sys.tables テーブルごとに 1 行 (外部テーブルを含む)。
sys.table_types データ型ごとに 1 行。

統計のシステム関数

次のシステム関数は統計の操作に役立ちます。

システム関数 説明
STATS_DATE 統計オブジェクトが最後に更新された日付。

1 つのビューへの統計列と関数の統合

このビューでは、STATS_DATE() 関数の統計と結果に関連する列が一緒に表示されます。

CREATE VIEW dbo.vstats_columns
AS
SELECT
        sm.[name]                           AS [schema_name]
,       tb.[name]                           AS [table_name]
,       st.[name]                           AS [stats_name]
,       st.[filter_definition]              AS [stats_filter_definition]
,       st.[has_filter]                     AS [stats_is_filtered]
,       STATS_DATE(st.[object_id],st.[stats_id])
                                            AS [stats_last_updated_date]
,       co.[name]                           AS [stats_column_name]
,       ty.[name]                           AS [column_type]
,       co.[max_length]                     AS [column_max_length]
,       co.[precision]                      AS [column_precision]
,       co.[scale]                          AS [column_scale]
,       co.[is_nullable]                    AS [column_is_nullable]
,       co.[collation_name]                 AS [column_collation_name]
,       QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
                                            AS two_part_name
,       QUOTENAME(DB_NAME())+'.'+QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name])
                                            AS three_part_name
FROM    sys.objects                         AS ob
JOIN    sys.stats           AS st ON    ob.[object_id]      = st.[object_id]
JOIN    sys.stats_columns   AS sc ON    st.[stats_id]       = sc.[stats_id]
                            AND         st.[object_id]      = sc.[object_id]
JOIN    sys.columns         AS co ON    sc.[column_id]      = co.[column_id]
                            AND         sc.[object_id]      = co.[object_id]
JOIN    sys.types           AS ty ON    co.[user_type_id]   = ty.[user_type_id]
JOIN    sys.tables          AS tb ON    co.[object_id]      = tb.[object_id]
JOIN    sys.schemas         AS sm ON    tb.[schema_id]      = sm.[schema_id]
WHERE   st.[user_created] = 1
;

次のステップ

専用 SQL プールのクエリ パフォーマンスをさらに向上させるには、「専用 SQL プールのワークロードとベスト プラクティスの監視」を参照してください

サーバーレス SQL プールのクエリ パフォーマンスをさらに向上させるには、「 サーバーレス SQL プールのベスト プラクティス」を参照してください。