専用 SQL Pool ベストプラクティス
Agenda
まずは自己紹介
念のために Synapse Analytics 専用 SQL Pool のおさらい
6
Azure
Data Lake Storage Gen2
専用 SQL Pool 占有ストレージに内部的に 60 個のデータベースを保持し、
Compute Node が均等に分担する
Core
NVMe SSD
Adaptive
Cache
Memory
TempDB
ノードは、NVMe SSD を搭載し、
SQL Engine は、Adaptive Cache に
列ストア セグメントをキャッシュ
⚫最大 60 ノード=DW30000c までスケール
⚫列ストアのデータサイズは無制限
ファイル
Polybase による並列ロード
(tempDB への一時格納)
Azure
Blob Storage
DB01
DB10
DB11
DB20
DB21
DB30
DB31
DB40
DB41
DB50
DB51
DB60
Compute
DMS
SQL Server
Compute
DMS
SQL Server
Compute
DMS
SQL Server
Compute
DMS
SQL Server
Compute
DMS
SQL Server
Compute
DMS
SQL Server
DW3000c の例
Control
DMS
SQL Server
Massively Parallel Processing (MPP) Engine
7
SQL Server / SQL Database とのアーキテクチャの差異を理解する
• スケールアウト型のアーキテクチャ=複数のコンピュート ノードで構成
• 1 つのテーブル データが 60 個のディストリビューション (DB) に分散して配置
• 各コンピュート ノードが、60 個のディストリビューションを均等に分担
• TempDB は、各ノードの NVMe SSD 上に配置
ポイント
• コンピュート ノード間でのデータ移動を極力発生させないようにする (特に Shuffle move の軽減)
• 各コンピュート ノードの処理負荷が均等になるようにする
• DW1000c 以上を極力利用する (DW500c ではコントロール ノードとコンピュート ノードが同居する構成)
• スケーラビリティは非常に高いが、同時実行数には限度がある
カラムストアの品質改善(一般的な効果:2~10倍)
性能改善前
分散方式の見直し(一般的な効果:2~5倍)
列統計の事前作成・更新(一般的な効果:特定の時間で 2~10倍)
レプリケートテーブルの事前準備(一般的な効果:特定の時間で 2~10倍)
データの偏りの是正/分散キー見直し(一般的な効果:2~5倍)
環境全体が
改善対象
チューニング実績 1:5 倍改善
チューニング実績 3:5 倍改善
チューニング実績 2:2 倍改善
チューニング実績 5:9 倍改善
チューニング実績 4:5 倍改善
ベースライン確立
2~5倍のスループット改善
環境のアセスメントと性能改善
⇒ Shuffle Move の軽減が有効
性能影響を
与えるクエリ
が改善対象
SELECT vs_id, a.ord, b.qty
FROM vendor_sales a
JOIN store_sales b ON a.vs_id = b.VID
WHERE a.color = 'Red'
Result Set
1,15, 5
Result Set
2,13, 3
分散キー
分散表
Final Result Set
1,15,5
2,13,3
実行SQL
⚫ ノード内で結合キーをもとに Join するために、store_sales を VID を分散キーとして Shuffle
⚫ 各コンピュートノード内で Join & 集計を実施
⚫ Shuffle Move は、個別のクエリとしても、システム全体のパフォーマンスに対しても影響を及ぼす
⚫ Shuffle Move は、完全に無くすことは難しいが、影響の大きいクエリにターゲットを集中することで改善可能 (分散キー見直し, Materialized View)
ss_id VID Qty
1 11 5
3 2 3
5 54 12
7 6 17
Store Sales
ss_id VID Qty
2 32 10
4 4 11
6 78 7
8 8 1
Store Sales
vs_id Color Ord
1 Red 15
3 Blue 20
5 Yellow 22
7 Green 17
Vendor Sales
vs_id Color Ord
2 Red 13
4 Blue 21
6 Yellow 27
8 Green 11
Vendor Sales
分散表
分散キー
ss_id VID Qty
1 1 5
2 3 10
5 5 12
6 7 7
一時Store Sales
ss_id VID Qty
3 2 3
4 4 11
7 6 17
8 8 1
一時Store Sales
VID を分散キーとして Shuffle (ノード間移動)
tempDB
tempDB
Synapse Analytics 専用 SQL Pool ベストプラクティス
Fact / Transaction 系のテーブルは、分散キーを設定し、ハッシュ分散させること
ファクト系テーブルは、ハッシュ分散させる
11
注意点
• デフォルト (分散キー未指定) だと、ラウンドロビンが選択されてしまう ⇒ データ移動が発生し易い
• 分散キーには、カージナリティの高い (バリエーションが多い) 列を選択すること ⇒ カージナリティが低いと、データの偏りが起き易い
• ジョインに良く利用される列を選択すること ⇒ データ移動の発生頻度が低くなる
CREATE TABLE [schema].[table_name]
(
~列定義~
)
WITH
(
CLUSTERED COLUMNSTORE INDEX
, DISTRIBUTION = HASH([distiribution_key_column_name])
)
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-distribute
Fact / Transaction 系のテーブルはハッシュ分散を選択するのが基本だが、適切なハッシュキーが
見つからず、結果として、データの偏りが大きい場合は、ラウンドロビンで分散させる
適切なハッシュキーが見つからなければ、ラウンドロビンで分散
12
CREATE TABLE [schema].[table_name]
(
~列定義~
)
WITH
(
CLUSTERED COLUMNSTORE INDEX
, DISTRIBUTION = ROUND_ROBIN
)
※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/create-table-azure-sql-data-warehouse?toc=%2Fazure%2Fsynapse-analytics%2Fsql-data-
warehouse%2Ftoc.json&bc=%2Fazure%2Fsynapse-analytics%2Fsql-data-warehouse%2Fbreadcrumb%2Ftoc.json&view=azure-sqldw-latest
物理サイズが 2 GB 程度を目安に、マスター系テーブルは、レプリケート テーブルにする
マスター系テーブルは、レプリケート テーブルを考慮する
13
注意点
• レプリケート テーブルは、各ノードにコピーされるが、更新が発生するとコピーは無効になる ⇒ 更新頻度の高いテーブルは不向き
• 各ノードのコピーが無効化されるのは、以下の条件となる
✓ データがロードされる、または、変更される
✓ Synapse SQL インスタンスが別のレベルにスケーリングされる
✓ テーブル定義が更新される
CREATE TABLE [schema].[table_name]
(
~列定義~
)
WITH
(
CLUSTERED COLUMNSTORE INDEX
, DISTRIBUTION = REPLICATE
)
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/design-guidance-for-replicated-tables
パーティションは、日付での効率的なロードや削除などの運用目的で設定し、パーティションのサイズ
が小さくなり過ぎないように注意する (例えば、2,000 万行は小さい)
細か過ぎるパーティションは設定しない
14
注意点
• 列ストア セグメントは、MIN/MAX 値をカタログに保持している為、I/O 効率が高い ⇒ I/O 効率目的だけでパーティションは設定しない
• パーティションを設定すると、パーティション数 × ディストリビューション (60) にテーブルが分割される為、列ストア セグメントの品質を落とす 可
能性が高くなる ⇒ 列ストア セグメントの品質 (I/O 効率) が最も良いのは 104 万行に近い値
CREATE TABLE [schema].[table_name]
(
~列定義~
)
WITH
(
CLUSTERED COLUMNSTORE INDEX
, DISTRIBUTION = HASH([distiribution_key_column_name])
, PARTITION([partition_column_name] RANGE RIGHT FOR VALUES
(20000101,20010101,20020101 ,20030101,20040101,20050101))
)
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-partition?toc=/azure/synapse-
analytics/toc.json&bc=/azure/synapse-analytics/breadcrumb/toc.json
条件句でよく利用される並び順が重要な列に順序指定 列ストア インデックスを適用して、
IO 効率を上げる
順序指定 列ストア インデックスを活用する
15
注意点
• 列ストア セグメントは、MIN/MAX 値をカタログに保持している為、I/O 効率が高い ⇒ Ordered CCI はこの特性に大きく寄与する
• 参照性能が速くなる一方、ロード性能との間でトレードオフが発生する為、性能検証を行い、バランスを考慮すること
CREATE TABLE [schema].[table_name]
(
~列定義~
)
WITH
(
CLUSTERED COLUMNSTORE INDEX ORDER ([order_column_name1],…)
, DISTRIBUTION = HASH([distiribution_key_column_name])
)
※参照: https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/performance-tuning-ordered-cci
データロード時のリソースクラスの値を適正化して、列ストア セグメント作成時のメモリ割り当てを十分
にする
列ストア セグメントの品質を上げる
16
注意点
• INSERT … SELECT や CREATE TABLE … AS SELECT などを使うと、メモリ上で列ストア セグメントを生成するが、カラム数が多いテーブルの場
合、多くのメモリ量を必要とする為、リソースクラスの値が小さ過ぎると、小さなセグメントが多数生成される ⇒ SELECT 時の I/O 量が増え、
性能が悪化する
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-memory-optimizations-for-columnstore-compression
テーブルの列数は 100 程度までを目安として適正化することで、列ストア セグメント生成時のメモリ
量を削減し、データロード負荷・時間を削減することができる
列数が多すぎるテーブルは作らない
17
注意点
• 列数の多いテーブルの場合、ロードだけでなく、SELECT * のレスポンスタイムも長くなる ⇒ 必要な列を指定して SELECT する
コントロールノードを介さず、コンピュートノードが並列ロード可能な Polybase (外部テーブル) か、COPY
句を利用することで、データロードを高速化する
データのロードには、Polybase か COPY 句を利用する
18
注意点
• ファイルデータをそのままテーブルにロードする場合、COPY 句を利用する (2020/09/23 GA)
• ファイルデータに対して、外部テーブル定義を介して、テーブルにロードするような場合、Polybase を利用する
• Azure Data Factory においても、Polybase と COPY 句を利用したロードが可能だが、指定しないと Bulk Copy API を使ったロードとなる
※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/copy-into-transact-sql?view=azure-sqldw-latest
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql/develop-tables-external-tables?tabs=sql-pool
最終系のテーブルではなく、中間的なテーブルとしてロードする場合、列ストアではなく、一
時ヒープテーブル (行ストア) としてロードすることで、プロセス全体を高速化できる
ステージング テーブルは、一時ヒープテーブルにロードする
19
注意点
• 一時テーブルは、NVMe SSD 上の TempDB に格納される ⇒ 高速だが、利用し過ぎると、ソート処理などに支障が出る
• 一時テーブルは、同一セッション内でのみ有効 ⇒ T-SQL バッチなどで一連の処理を実行
CREATE TABLE #temp_table_name
WITH
(
HEAP
, DISTRIBUTION = HASH([distiribution_key_column_name])
)
AS
SELECT *
FROM [schema].[external_table_name]
処理特性 (メモリの消費量) に応じて、静的リソースクラス (staticrc10~80) をユーザー/ロールに
割り当て、全体的な同時実行数を調整する
リソースクラスを指定して、メモリ割り当てと同時実行数を制御する
20
注意点
• Synapse SQL のスケール (DWU) 毎に最大同時実行数は決まっている ⇒ DW6000c 以上で最大 128 同時実行
• リソースクラスは、コンピューティングリソース (CPU/メモリ) を分離する機能ではない ⇒ 実行時のワーキングメモリを調整するのみ
• スケール毎のスロット量とリソースクラス毎の消費スロットという概念で同時実行数を制御
• 動的リソースクラスは、最大 32 同時実行に制限されている為、原則として静的リソースクラスを活用
• 最大同時実行数を上回るリクエストは、キューで実行待ちとなる
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/memory-concurrency-limits
※参照: https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/resource-classes-for-workload-management
リソースクラスによって管理される処理
• INSERT-SELECT、UPDATE、DELETE
• SELECT (ユーザー テーブルのクエリを実行する場合)
• ALTER INDEX - REBUILD または REORGANIZE
• ALTER TABLE REBUILD
• CREATE INDEX
• CREATE CLUSTERED COLUMNSTORE INDEX
• CREATE TABLE AS SELECT (CTAS)
• データロード (Bulk Copy API など)
• Data Movement Service (DMS) によって実行されるデータ移動操作
リソースクラスによって管理されない処理 (smallrc で動作)
• CREATE または DROP TABLE
• このパーティション テーブルでは、ALTER TABLE ...SWITCH、SPLIT、または MERGE PARTITION
• ALTER INDEX DISABLE
• DROP INDEX
• CREATE、UPDATE、または DROP STATISTICS
• TRUNCATE TABLE
• ALTER AUTHORIZATION
• CREATE LOGIN
• CREATE、ALTER、または DROP USER
• CREATE、ALTER、または DROP PROCEDURE
• CREATE または DROP VIEW
• INSERT VALUES
• システム ビューおよび DMV からの SELECT
• EXPLAIN
• DBCC
ワークロード グループ内 (ワークロード未設定時は、共有プール内) において、特定処理 (リクエスト)
のキュー内の順番をスキップ (優先) させることができる
ワークロードの重要度を使用して、特定処理の順番を優先させる
21
注意点
• ワークロード分類子を利用して、重要度 (IMPORTANCE = low/below_normal/normal/above_normal/high) を設定する
• この機能によって影響を及ぼすのは、キュー内の順番のみ
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-workload-importance
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-how-to-configure-workload-importance
---------------------------------------------
-- ワークロード分類子の作成
-- (ユーザー/ロールをワークロードグループへ割付ける)
---------------------------------------------
--// マネージャー層のリクエストを優先
CREATE WORKLOAD CLASSIFIER WCls_B2C
WITH
(
WORKLOAD_GROUP = ’staticrc40’, --共有プール対象の場合、リソースクラス
MEMBERNAME = 'Role_managers’,
IMPORTANCE = ’above_normal'
)
結果セット キャッシュにヒットすると、コントロールノードですぐに結果が返却される為、リソース利用率
を削減し、レスポンスを向上させることができる
結果セット キャッシュ (Result set caching) を有効化する
22
注意点
• 参照先のテーブルが更新されると、キャッシュは無効になる ⇒ 更新が頻繁な環境には向かない
• 結果セット キャッシュのサイズは、データベース全体で 1 TB
• キャッシュされない場合
✓ DateTime.Now() などの非決定論的関数を使用するクエリ
✓ ユーザー定義関数を使用したクエリ
✓ 行レベルのセキュリティまたは列レベルのセキュリティが有効になっているテーブルを使用したクエリ
✓ 64 KB を超える行サイズのデータを返すクエリ 10 GB を超えるサイズの大きなデータを返すクエリ
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/performance-tuning-result-set-caching
-- データベースで有効化
ALTER DATABASE [database_name]
SET RESULT_SET_CACHING ON;
-- セッション単位で無効化
SET RESULT_SET_CACHING OFF
SELECT TOP 1 * or COUNT_BIG(*) を使い、レプリケート テーブルを事前に各ノードにコピーしておく
レプリケート テーブルは事前に Ready にしておく
23
注意点
• 各ノードのコピーが無効化 されるのは、以下の条件となる
✓ データがロードされる、または、変更される
✓ Synapse SQL インスタンスが別のレベルにスケーリングされる
✓ テーブル定義が更新される
• レプリケート テーブルは、最初の参照時に各ノードの保持する 1 つ目のディストリビューションにコピーされる ⇒ 性能影響が大きい
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/design-guidance-for-replicated-tables
-- レプリケート テーブルの状態
SELECT [ReplicatedTable] = t.[name]
FROM sys.tables t
JOIN sys.pdw_replicated_table_cache_state c ON c.object_id = t.object_id
JOIN sys.pdw_table_distribution_properties p ON p.object_id = t.object_id
WHERE c.[state] = 'NotReady' AND p.[distribution_policy_desc] = 'REPLICATE'
-- レプリケートのコピー(以下のどちらかを利用)
SELECT TOP 1 * FROM [schema].[table_name];
SELECT COUNT_BIG(*) FROM [schema].[table_name];
列統計は自動作成には任せず、ロードジョブの必須ステップとして事前に作成しておく
列統計は事前に作成しておく
24
注意点
• 列統計は最初のクエリ実行時に自動作成される ⇒ 性能影響が大きい
• 列統計の自動作成では、クエリの WHERE 句内の列 と 結合キーの列が対象となる
• 列統計の自動作成時は、サンプリング (10 億行未満:20% / 10 億行以上:2%)
• 20% のサンプリングで十分な場合も多いが、大きな値や WITH FULLSCAN 指定の方が精度は上がる
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-statistics#examples-create-statistics
-- 単一列統計の作成
CREATE STATISTICS [statistics_name] ON [schema].[table_name]([column_name]) WITH
20 PERCENT;
差分更新 (非洗い替え) テーブルの列統計は、ロード処理後に更新する
差分更新テーブルの列統計を更新する
25
注意点
• 列統計は最初のクエリ実行時に自動作成される ⇒ 性能影響が大きい
• 列統計の自動作成では、クエリの WHERE 句内の列 と 結合キーの列が対象となる
• 列統計の自動更新は、既定では無効
-------------------------------------------------------------------------------
-- 更新対象の把握と、統計詳細取得コマンド&統計更新コマンドの自動生成
-------------------------------------------------------------------------------
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],
'DBCC SHOW_STATISTICS(''[' + sm.[name] + '].[' + tb.[name] + ']'',''' + st.[name] + ''')' SHOW_STATS_COMMAND,
'UPDATE STATISTICS [' + sm.[name] + '].[' + tb.[name] + ']([' + st.[name] + ']) WITH SAMPLE 20 PERCENT' UPDATE_COMMAND
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.[object_id] = OBJECT_ID('nct.T100_packet_tcp') --★テーブル名を指定
AND STATS_DATE(st.[object_id],st.[stats_id]) IS NOT NULL
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-statistics#examples-update-statistics
※参照:https://docs.microsoft.com/ja-jp/sql/relational-databases/statistics/view-statistics-properties?view=sql-server-ver15
DROP/TRUNCATE が使えない場合、1 件単位の DELETE ではなく、DELETE 対象キーのみの
テーブルをロードし、そのテーブルとジョインして一括削除を行う
データの削除は、まとめて行う
26
注意点
• DELETE に限らず、INSERT/UPDATE も 1 件単位の DML を繰り返し行うのではなく、処理をまとめて実行すること
• Synapse SQL は、大量処理、大容量のスキャンが超高速である為、その特性を生かす処理を行う
---------------------------------------------
-- まとめて削除
---------------------------------------------
--// 削除対象キーテーブルとジョインして、一括削除
DELETE t1 FROM dbo.T1 t1
INNER JOIN dbo.deleteKeysForT1 tg on t1.key1 = tg.key1
ユーザー定義関数 (UDF) は、なるべく作成せず、特に大規模なテーブルを対象としたクエリには
利用しない
ユーザー定義関数 (UDF) は、なるべく使わない
27
注意点
• UDF は、並列処理を阻害する場合があり、性能に甚大な影響を与えることがある
• 極力、組み込み関数の組み合わせで対応する
クエリで条件比較やジョインを使う場合、UNICODE 型 (NCHAR/NVARCHAR) と非 UNICODE 型
(CHAR/VARCHAR) を混在させない
条件比較/結合でUNICODE 型と非 UNICODE 型を混在させない
28
注意点
• A (NVARCHAR) = B (VARCHAR) で比較/結合した場合、B は UNICODE に変換される為、性能に大きな影響が出る
• JDBC Driver を経由したパラメータ化文字列は既定では UNICODE で送信される
• 文字列は UNICODE 型を基本にしておく
T-SQL では、複数のクエリを一つのバッチとして実行できる為、無理してサブクエリ化したような
クエリは、ステップ分けした方が大幅に性能向上できる場合がある
(例: Exadata 40分 / Synapse SQL 当初 60分超 ⇒ 3.5分)
T-SQL のメリットを最大化する
29
--------------------------------------------------------------------------
-- Query-1 の結果が1件 ★インメモリ
--------------------------------------------------------------------------
--// 個別変数
DECLARE @DeviceId NCHAR(10)
DECLARE @Temperature INT
--// Query-1
SELECT TOP 1 @DeviceId = DeviceId, @Temperature = Temperature
FROM dbo.asalog ORDER BY Temperature DESC;
--// Query-2
SELECT a.*, @Temperature Temperature FROM dbo.asalog a
WHERE a.DeviceId = @DeviceId;
--------------------------------------------------------------------------
-- Query-1 の結果が小規模 (~数万件) ★インメモリ
--------------------------------------------------------------------------
--// テーブル変数
DECLARE @tableVal TABLE
(
DeviceId NCHAR(10),
Temperature INT
)
--// Query-1
INSERT INTO @tableVal
SELECT TOP 1000 * FROM dbo.asalog ORDER BY Temperature DESC;
--// Query-2
SELECT a.*, t.Temperature FROM dbo.asalog a
INNER JOIN @tableVal t ON a.DeviceId = t.DeviceId;
--------------------------------------------------------------------------
-- Query-1 の結果が中規模 (~数十万件) ★インメモリ
-- CTE (Common Table Expression) の利用
--------------------------------------------------------------------------
--// CTE (Common Table Expression)
WITH table_cte (DeviceId, Temperature)
AS
(
--// Query-1
SELECT TOP 100000 * FROM dbo.asalog ORDER BY Temperature DESC
)
--// Query-2
SELECT a.*, t.Temperature FROM dbo.asalog a
INNER JOIN table_cte t ON a.DeviceId = t.DeviceId;
--------------------------------------------------------------------------
-- Query-1 の結果が大規模 (数百万件以上) ★一時テーブル on tempDB
-- SQLDB BC/Hyperscale, Synapse SQL の場合、tempDB は NVMe SSD 上なので高速
--------------------------------------------------------------------------
--// 一時テーブル削除
IF OBJECT_ID(N'tempdb..#table1',N'U') IS NOT NULL
DROP TABLE #table1;
--// Query-1 to 一時テーブル
SELECT TOP 2000000 * INTO #table1 FROM dbo.asalog ORDER BY Temperature DESC;
--// Query-2
SELECT a.*, t.Temperature FROM dbo.asalog a
INNER JOIN #table1 t ON a.DeviceId = t.DeviceId;
⚫ UPDATE よりも、DELETE & INSERT の方が高速
⚫ MERGE 文が利用できるようになった (2020/09/23)
その他、DML 処理の Tips
30
※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15
Synapse Analytics 専用 SQL Pool パフォーマンスチューニング
チェック対象:1 分集計とした以下のメトリクスをチェックし、定常的に負荷が高い場合、DWU 追加を検討
• CPU used percentage 最大値
• Memory used percentage 最大値
• Local tempDB used percentage 最大値 (ソート, データ移動, Polybase によるロード, 一時テーブルで利用)
• Adaptive cache hit percentage 平均値 (クエリ実行時に列ストアデータが NVMe SSD に載っている割合) ⇒ 80% 以上が目安
• Workload group active queries 合計
• Workload group queued queries 合計 ⇒ 定常的にキュー待ちが大量に起きていないか
キャパシティが足りているかどうかをチェック
32
チェック対象:以下クエリ実行時の [COMPRESSED_rowgroup_rows_XXX] 列の値は、104 万行に近いほど品質が良い
問題の原因:データロード時のリソースクラス or ワークロード グループの REQUEST_MIN_RESOURCE_GRANT_PERCENT の値が小さ過ぎる
列ストア セグメントの品質を疑う
33
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-index#optimizing-clustered-columnstore-indexes
----------------------------------------------------------------------------------
-- CCI セグメント品質のチェック (簡易版)
----------------------------------------------------------------------------------
-- [table_partition_count] パーティション数
-- [row_count_total] トータル行数
-- [COMPRESSED_rowgroup_rows] 圧縮済み行グループのトータル行数
-- [COMPRESSED_rowgroup_rows_MIN] 圧縮済み行グループ内の最小行数
-- [COMPRESSED_rowgroup_rows_MAX] 圧縮済み行グループ内の最大行数
-- [COMPRESSED_rowgroup_rows_AVG] 圧縮済み行グループ内の平均行数
-- [COMPRESSED_rowgroup_rows_DELETED] 行グループ内の論理削除された行数
----------------------------------------------------------------------------------
SELECT
s.name AS [schema_name]
, t.name AS [table_name]
, COUNT(DISTINCT rg.[partition_number]) AS [table_partition_count]
, SUM(rg.[total_rows]) AS [row_count_total]
, SUM(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE 0 END) AS [COMPRESSED_rowgroup_rows]
, AVG(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_AVG]
, MIN(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_MIN]
, MAX(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_MAX]
, SUM(CASE WHEN rg.[State] = 3 THEN rg.[deleted_rows] ELSE 0 END) AS [COMPRESSED_rowgroup_rows_DELETED]
, SUM(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE 0 END) AS [OPEN_rowgroup_rows]
, AVG(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_AVG]
, MIN(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_MIN]
, MAX(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_MAX]
, 'ALTER INDEX ALL ON ' + s.name + '.' + t.NAME + ' REBUILD;' AS [Rebuild_Index_SQL]
FROM sys.[pdw_nodes_column_store_row_groups] rg
JOIN sys.[pdw_nodes_tables] nt ON rg.[object_id] = nt.[object_id]
AND rg.[pdw_node_id] = nt.[pdw_node_id]
AND rg.[distribution_id] = nt.[distribution_id]
JOIN sys.[pdw_table_mappings] mp ON nt.[name] = mp.[physical_name]
JOIN sys.[tables] t ON mp.[object_id] = t.[object_id]
JOIN sys.[schemas] s ON t.[schema_id] = s.[schema_id]
--WHERE s.name = @schemaName AND t.name = @tableName
GROUP BY s.[name], t.[name]
ORDER BY s.[name], t.[name]
チェック対象:以下クエリ実行時の [distribution_id] 列毎の [row_count] 列の値を見て、片寄りが無いかを確認
問題の原因:分散キーに設定した列が適切で無い (=カージナリティが低い or 値に片寄りがある) 可能性が高い
ディストリビューションのデータの偏りを疑う
34
※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-distribute#determine-if-the-table-has-data-skew
★dbo.vTableSizes ビューは、参照先のリンクに定義がある
----------------------------------------------------------------------------------
-- 特定のノード/ディストリビューションにデータの偏りがないかのチェック
----------------------------------------------------------------------------------
-- 特定のテーブルについてノードにデータの片寄りが無いか
DBCC PDW_SHOWSPACEUSED('schema_name.table_name');
-- ディストリビューションの 10% 以上の偏りを抽出
select
two_part_name
, pdw_node_id
, pdw_node_type
, distribution_id
, dist_name,partition_nmbr
, row_count
, distribution_column
, distribution_policy_name
, index_type_desc
from dbo.vTableSizes -- ★★ このビューは、参照先のリンクにスクリプトがある
where two_part_name in
(
select two_part_name
from dbo.vTableSizes
where row_count > 0
group by two_part_name
having (max(row_count * 1.000) - min(row_count * 1.000))/max(row_count * 1.000) >= .10
)
order by two_part_name, distribution_id, row_count
;
チェック対象:以下クエリ実行時の [operation_type] 列毎の [total_elapsed_time], [row_count] の値を見て、時間・件数が大きくないか確認
問題の原因:
• BroadcastMoveOperation (全データを全ノードへ移動) :レプリケート テーブル適用について検討が必要
• ShuffleMoveOperation (ジョインに必要なデータの移動):ノード内でジョインが完結していない ⇒ 結合キー (列) を分散キーに出来ないか検討が必要
コンピュート ノード間でデータ移動が大量に発生していないか疑う
35
※参照:https://docs.microsoft.com/ja-jp/sql/relational-databases/system-dynamic-management-views/sys-dm-pdw-request-steps-transact-sql?toc=/azure/synapse-analytics/sql-data-
warehouse/toc.json&bc=/azure/synapse-analytics/sql-data-warehouse/breadcrumb/toc.json&view=azure-sqldw-latest
--------------------------------------------
-- コンピュートノード間でのデータ移動を確認
--------------------------------------------
-- 完了した対象のクエリの QID を確認
SELECT *
FROM sys.dm_pdw_exec_requests
WHERE status in ('Completed','Failed','Cancelled')
AND session_id <> session_id()
ORDER BY submit_time DESC;
-- 分散実行プランでデータ移動が大量に発生していないか確認
-- (BroadcastMoveOperation, ShuffleMoveOperation が対象)
DECLARE @qid VARCHAR(20) = ’QIDxxxxxx’;
SELECT * FROM sys.dm_pdw_request_steps
WHERE request_id = @qid
ORDER BY step_index;
Shuffle Move の軽減方法
分散キーの見直し以外では、Materialized View (MV) の利用が最も効果的
• オプティマイザーによって適切な MV が提案される
• EXPLAIN WITH_RECOMMENDATIONS + SQL クエリによって、推奨される MV 作成スクリプトが提示される
• EXPLAIN コマンドによって出力された実行プランを見ることで、Shuffle Move の有無、および、どのカラムで Shuffle しようとしているかを確
認することができる
例) 出力された実行プラン (XML) に、MV の候補が提示される 例) 出力された実行プラン (XML) に、Shuffle Move の情報を確認
クエリに 「*」 指定していないかをチェック
37
チェック対象:SELECT * のように列を指定していないクエリかどうかを確認
問題の原因:列ストアで、列数の多いテーブルの場合、読み込むカタログ情報や I/O 対象となるセグメントの数が大量になるため
Azure Synapse Analytics 専用SQL Poolベストプラクティス

Azure Synapse Analytics 専用SQL Poolベストプラクティス

  • 1.
    専用 SQL Poolベストプラクティス
  • 2.
  • 3.
  • 5.
    念のために Synapse Analytics専用 SQL Pool のおさらい
  • 6.
    6 Azure Data Lake StorageGen2 専用 SQL Pool 占有ストレージに内部的に 60 個のデータベースを保持し、 Compute Node が均等に分担する Core NVMe SSD Adaptive Cache Memory TempDB ノードは、NVMe SSD を搭載し、 SQL Engine は、Adaptive Cache に 列ストア セグメントをキャッシュ ⚫最大 60 ノード=DW30000c までスケール ⚫列ストアのデータサイズは無制限 ファイル Polybase による並列ロード (tempDB への一時格納) Azure Blob Storage DB01 DB10 DB11 DB20 DB21 DB30 DB31 DB40 DB41 DB50 DB51 DB60 Compute DMS SQL Server Compute DMS SQL Server Compute DMS SQL Server Compute DMS SQL Server Compute DMS SQL Server Compute DMS SQL Server DW3000c の例 Control DMS SQL Server Massively Parallel Processing (MPP) Engine
  • 7.
    7 SQL Server /SQL Database とのアーキテクチャの差異を理解する • スケールアウト型のアーキテクチャ=複数のコンピュート ノードで構成 • 1 つのテーブル データが 60 個のディストリビューション (DB) に分散して配置 • 各コンピュート ノードが、60 個のディストリビューションを均等に分担 • TempDB は、各ノードの NVMe SSD 上に配置 ポイント • コンピュート ノード間でのデータ移動を極力発生させないようにする (特に Shuffle move の軽減) • 各コンピュート ノードの処理負荷が均等になるようにする • DW1000c 以上を極力利用する (DW500c ではコントロール ノードとコンピュート ノードが同居する構成) • スケーラビリティは非常に高いが、同時実行数には限度がある
  • 8.
    カラムストアの品質改善(一般的な効果:2~10倍) 性能改善前 分散方式の見直し(一般的な効果:2~5倍) 列統計の事前作成・更新(一般的な効果:特定の時間で 2~10倍) レプリケートテーブルの事前準備(一般的な効果:特定の時間で 2~10倍) データの偏りの是正/分散キー見直し(一般的な効果:2~5倍) 環境全体が 改善対象 チューニング実績1:5 倍改善 チューニング実績 3:5 倍改善 チューニング実績 2:2 倍改善 チューニング実績 5:9 倍改善 チューニング実績 4:5 倍改善 ベースライン確立 2~5倍のスループット改善 環境のアセスメントと性能改善 ⇒ Shuffle Move の軽減が有効 性能影響を 与えるクエリ が改善対象
  • 9.
    SELECT vs_id, a.ord,b.qty FROM vendor_sales a JOIN store_sales b ON a.vs_id = b.VID WHERE a.color = 'Red' Result Set 1,15, 5 Result Set 2,13, 3 分散キー 分散表 Final Result Set 1,15,5 2,13,3 実行SQL ⚫ ノード内で結合キーをもとに Join するために、store_sales を VID を分散キーとして Shuffle ⚫ 各コンピュートノード内で Join & 集計を実施 ⚫ Shuffle Move は、個別のクエリとしても、システム全体のパフォーマンスに対しても影響を及ぼす ⚫ Shuffle Move は、完全に無くすことは難しいが、影響の大きいクエリにターゲットを集中することで改善可能 (分散キー見直し, Materialized View) ss_id VID Qty 1 11 5 3 2 3 5 54 12 7 6 17 Store Sales ss_id VID Qty 2 32 10 4 4 11 6 78 7 8 8 1 Store Sales vs_id Color Ord 1 Red 15 3 Blue 20 5 Yellow 22 7 Green 17 Vendor Sales vs_id Color Ord 2 Red 13 4 Blue 21 6 Yellow 27 8 Green 11 Vendor Sales 分散表 分散キー ss_id VID Qty 1 1 5 2 3 10 5 5 12 6 7 7 一時Store Sales ss_id VID Qty 3 2 3 4 4 11 7 6 17 8 8 1 一時Store Sales VID を分散キーとして Shuffle (ノード間移動) tempDB tempDB
  • 10.
    Synapse Analytics 専用SQL Pool ベストプラクティス
  • 11.
    Fact / Transaction系のテーブルは、分散キーを設定し、ハッシュ分散させること ファクト系テーブルは、ハッシュ分散させる 11 注意点 • デフォルト (分散キー未指定) だと、ラウンドロビンが選択されてしまう ⇒ データ移動が発生し易い • 分散キーには、カージナリティの高い (バリエーションが多い) 列を選択すること ⇒ カージナリティが低いと、データの偏りが起き易い • ジョインに良く利用される列を選択すること ⇒ データ移動の発生頻度が低くなる CREATE TABLE [schema].[table_name] ( ~列定義~ ) WITH ( CLUSTERED COLUMNSTORE INDEX , DISTRIBUTION = HASH([distiribution_key_column_name]) ) ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-distribute
  • 12.
    Fact / Transaction系のテーブルはハッシュ分散を選択するのが基本だが、適切なハッシュキーが 見つからず、結果として、データの偏りが大きい場合は、ラウンドロビンで分散させる 適切なハッシュキーが見つからなければ、ラウンドロビンで分散 12 CREATE TABLE [schema].[table_name] ( ~列定義~ ) WITH ( CLUSTERED COLUMNSTORE INDEX , DISTRIBUTION = ROUND_ROBIN ) ※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/create-table-azure-sql-data-warehouse?toc=%2Fazure%2Fsynapse-analytics%2Fsql-data- warehouse%2Ftoc.json&bc=%2Fazure%2Fsynapse-analytics%2Fsql-data-warehouse%2Fbreadcrumb%2Ftoc.json&view=azure-sqldw-latest
  • 13.
    物理サイズが 2 GB程度を目安に、マスター系テーブルは、レプリケート テーブルにする マスター系テーブルは、レプリケート テーブルを考慮する 13 注意点 • レプリケート テーブルは、各ノードにコピーされるが、更新が発生するとコピーは無効になる ⇒ 更新頻度の高いテーブルは不向き • 各ノードのコピーが無効化されるのは、以下の条件となる ✓ データがロードされる、または、変更される ✓ Synapse SQL インスタンスが別のレベルにスケーリングされる ✓ テーブル定義が更新される CREATE TABLE [schema].[table_name] ( ~列定義~ ) WITH ( CLUSTERED COLUMNSTORE INDEX , DISTRIBUTION = REPLICATE ) ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/design-guidance-for-replicated-tables
  • 14.
    パーティションは、日付での効率的なロードや削除などの運用目的で設定し、パーティションのサイズ が小さくなり過ぎないように注意する (例えば、2,000 万行は小さい) 細か過ぎるパーティションは設定しない 14 注意点 •列ストア セグメントは、MIN/MAX 値をカタログに保持している為、I/O 効率が高い ⇒ I/O 効率目的だけでパーティションは設定しない • パーティションを設定すると、パーティション数 × ディストリビューション (60) にテーブルが分割される為、列ストア セグメントの品質を落とす 可 能性が高くなる ⇒ 列ストア セグメントの品質 (I/O 効率) が最も良いのは 104 万行に近い値 CREATE TABLE [schema].[table_name] ( ~列定義~ ) WITH ( CLUSTERED COLUMNSTORE INDEX , DISTRIBUTION = HASH([distiribution_key_column_name]) , PARTITION([partition_column_name] RANGE RIGHT FOR VALUES (20000101,20010101,20020101 ,20030101,20040101,20050101)) ) ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-partition?toc=/azure/synapse- analytics/toc.json&bc=/azure/synapse-analytics/breadcrumb/toc.json
  • 15.
    条件句でよく利用される並び順が重要な列に順序指定 列ストア インデックスを適用して、 IO効率を上げる 順序指定 列ストア インデックスを活用する 15 注意点 • 列ストア セグメントは、MIN/MAX 値をカタログに保持している為、I/O 効率が高い ⇒ Ordered CCI はこの特性に大きく寄与する • 参照性能が速くなる一方、ロード性能との間でトレードオフが発生する為、性能検証を行い、バランスを考慮すること CREATE TABLE [schema].[table_name] ( ~列定義~ ) WITH ( CLUSTERED COLUMNSTORE INDEX ORDER ([order_column_name1],…) , DISTRIBUTION = HASH([distiribution_key_column_name]) ) ※参照: https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/performance-tuning-ordered-cci
  • 16.
    データロード時のリソースクラスの値を適正化して、列ストア セグメント作成時のメモリ割り当てを十分 にする 列ストア セグメントの品質を上げる 16 注意点 •INSERT … SELECT や CREATE TABLE … AS SELECT などを使うと、メモリ上で列ストア セグメントを生成するが、カラム数が多いテーブルの場 合、多くのメモリ量を必要とする為、リソースクラスの値が小さ過ぎると、小さなセグメントが多数生成される ⇒ SELECT 時の I/O 量が増え、 性能が悪化する ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-memory-optimizations-for-columnstore-compression
  • 17.
    テーブルの列数は 100 程度までを目安として適正化することで、列ストアセグメント生成時のメモリ 量を削減し、データロード負荷・時間を削減することができる 列数が多すぎるテーブルは作らない 17 注意点 • 列数の多いテーブルの場合、ロードだけでなく、SELECT * のレスポンスタイムも長くなる ⇒ 必要な列を指定して SELECT する
  • 18.
    コントロールノードを介さず、コンピュートノードが並列ロード可能な Polybase (外部テーブル)か、COPY 句を利用することで、データロードを高速化する データのロードには、Polybase か COPY 句を利用する 18 注意点 • ファイルデータをそのままテーブルにロードする場合、COPY 句を利用する (2020/09/23 GA) • ファイルデータに対して、外部テーブル定義を介して、テーブルにロードするような場合、Polybase を利用する • Azure Data Factory においても、Polybase と COPY 句を利用したロードが可能だが、指定しないと Bulk Copy API を使ったロードとなる ※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/copy-into-transact-sql?view=azure-sqldw-latest ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql/develop-tables-external-tables?tabs=sql-pool
  • 19.
    最終系のテーブルではなく、中間的なテーブルとしてロードする場合、列ストアではなく、一 時ヒープテーブル (行ストア) としてロードすることで、プロセス全体を高速化できる ステージングテーブルは、一時ヒープテーブルにロードする 19 注意点 • 一時テーブルは、NVMe SSD 上の TempDB に格納される ⇒ 高速だが、利用し過ぎると、ソート処理などに支障が出る • 一時テーブルは、同一セッション内でのみ有効 ⇒ T-SQL バッチなどで一連の処理を実行 CREATE TABLE #temp_table_name WITH ( HEAP , DISTRIBUTION = HASH([distiribution_key_column_name]) ) AS SELECT * FROM [schema].[external_table_name]
  • 20.
    処理特性 (メモリの消費量) に応じて、静的リソースクラス(staticrc10~80) をユーザー/ロールに 割り当て、全体的な同時実行数を調整する リソースクラスを指定して、メモリ割り当てと同時実行数を制御する 20 注意点 • Synapse SQL のスケール (DWU) 毎に最大同時実行数は決まっている ⇒ DW6000c 以上で最大 128 同時実行 • リソースクラスは、コンピューティングリソース (CPU/メモリ) を分離する機能ではない ⇒ 実行時のワーキングメモリを調整するのみ • スケール毎のスロット量とリソースクラス毎の消費スロットという概念で同時実行数を制御 • 動的リソースクラスは、最大 32 同時実行に制限されている為、原則として静的リソースクラスを活用 • 最大同時実行数を上回るリクエストは、キューで実行待ちとなる ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/memory-concurrency-limits ※参照: https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/resource-classes-for-workload-management リソースクラスによって管理される処理 • INSERT-SELECT、UPDATE、DELETE • SELECT (ユーザー テーブルのクエリを実行する場合) • ALTER INDEX - REBUILD または REORGANIZE • ALTER TABLE REBUILD • CREATE INDEX • CREATE CLUSTERED COLUMNSTORE INDEX • CREATE TABLE AS SELECT (CTAS) • データロード (Bulk Copy API など) • Data Movement Service (DMS) によって実行されるデータ移動操作 リソースクラスによって管理されない処理 (smallrc で動作) • CREATE または DROP TABLE • このパーティション テーブルでは、ALTER TABLE ...SWITCH、SPLIT、または MERGE PARTITION • ALTER INDEX DISABLE • DROP INDEX • CREATE、UPDATE、または DROP STATISTICS • TRUNCATE TABLE • ALTER AUTHORIZATION • CREATE LOGIN • CREATE、ALTER、または DROP USER • CREATE、ALTER、または DROP PROCEDURE • CREATE または DROP VIEW • INSERT VALUES • システム ビューおよび DMV からの SELECT • EXPLAIN • DBCC
  • 21.
    ワークロード グループ内 (ワークロード未設定時は、共有プール内)において、特定処理 (リクエスト) のキュー内の順番をスキップ (優先) させることができる ワークロードの重要度を使用して、特定処理の順番を優先させる 21 注意点 • ワークロード分類子を利用して、重要度 (IMPORTANCE = low/below_normal/normal/above_normal/high) を設定する • この機能によって影響を及ぼすのは、キュー内の順番のみ ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-workload-importance ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-how-to-configure-workload-importance --------------------------------------------- -- ワークロード分類子の作成 -- (ユーザー/ロールをワークロードグループへ割付ける) --------------------------------------------- --// マネージャー層のリクエストを優先 CREATE WORKLOAD CLASSIFIER WCls_B2C WITH ( WORKLOAD_GROUP = ’staticrc40’, --共有プール対象の場合、リソースクラス MEMBERNAME = 'Role_managers’, IMPORTANCE = ’above_normal' )
  • 22.
    結果セット キャッシュにヒットすると、コントロールノードですぐに結果が返却される為、リソース利用率 を削減し、レスポンスを向上させることができる 結果セット キャッシュ(Result set caching) を有効化する 22 注意点 • 参照先のテーブルが更新されると、キャッシュは無効になる ⇒ 更新が頻繁な環境には向かない • 結果セット キャッシュのサイズは、データベース全体で 1 TB • キャッシュされない場合 ✓ DateTime.Now() などの非決定論的関数を使用するクエリ ✓ ユーザー定義関数を使用したクエリ ✓ 行レベルのセキュリティまたは列レベルのセキュリティが有効になっているテーブルを使用したクエリ ✓ 64 KB を超える行サイズのデータを返すクエリ 10 GB を超えるサイズの大きなデータを返すクエリ ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/performance-tuning-result-set-caching -- データベースで有効化 ALTER DATABASE [database_name] SET RESULT_SET_CACHING ON; -- セッション単位で無効化 SET RESULT_SET_CACHING OFF
  • 23.
    SELECT TOP 1* or COUNT_BIG(*) を使い、レプリケート テーブルを事前に各ノードにコピーしておく レプリケート テーブルは事前に Ready にしておく 23 注意点 • 各ノードのコピーが無効化 されるのは、以下の条件となる ✓ データがロードされる、または、変更される ✓ Synapse SQL インスタンスが別のレベルにスケーリングされる ✓ テーブル定義が更新される • レプリケート テーブルは、最初の参照時に各ノードの保持する 1 つ目のディストリビューションにコピーされる ⇒ 性能影響が大きい ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/design-guidance-for-replicated-tables -- レプリケート テーブルの状態 SELECT [ReplicatedTable] = t.[name] FROM sys.tables t JOIN sys.pdw_replicated_table_cache_state c ON c.object_id = t.object_id JOIN sys.pdw_table_distribution_properties p ON p.object_id = t.object_id WHERE c.[state] = 'NotReady' AND p.[distribution_policy_desc] = 'REPLICATE' -- レプリケートのコピー(以下のどちらかを利用) SELECT TOP 1 * FROM [schema].[table_name]; SELECT COUNT_BIG(*) FROM [schema].[table_name];
  • 24.
    列統計は自動作成には任せず、ロードジョブの必須ステップとして事前に作成しておく 列統計は事前に作成しておく 24 注意点 • 列統計は最初のクエリ実行時に自動作成される ⇒性能影響が大きい • 列統計の自動作成では、クエリの WHERE 句内の列 と 結合キーの列が対象となる • 列統計の自動作成時は、サンプリング (10 億行未満:20% / 10 億行以上:2%) • 20% のサンプリングで十分な場合も多いが、大きな値や WITH FULLSCAN 指定の方が精度は上がる ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-statistics#examples-create-statistics -- 単一列統計の作成 CREATE STATISTICS [statistics_name] ON [schema].[table_name]([column_name]) WITH 20 PERCENT;
  • 25.
    差分更新 (非洗い替え) テーブルの列統計は、ロード処理後に更新する 差分更新テーブルの列統計を更新する 25 注意点 •列統計は最初のクエリ実行時に自動作成される ⇒ 性能影響が大きい • 列統計の自動作成では、クエリの WHERE 句内の列 と 結合キーの列が対象となる • 列統計の自動更新は、既定では無効 ------------------------------------------------------------------------------- -- 更新対象の把握と、統計詳細取得コマンド&統計更新コマンドの自動生成 ------------------------------------------------------------------------------- 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], 'DBCC SHOW_STATISTICS(''[' + sm.[name] + '].[' + tb.[name] + ']'',''' + st.[name] + ''')' SHOW_STATS_COMMAND, 'UPDATE STATISTICS [' + sm.[name] + '].[' + tb.[name] + ']([' + st.[name] + ']) WITH SAMPLE 20 PERCENT' UPDATE_COMMAND 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.[object_id] = OBJECT_ID('nct.T100_packet_tcp') --★テーブル名を指定 AND STATS_DATE(st.[object_id],st.[stats_id]) IS NOT NULL ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-statistics#examples-update-statistics ※参照:https://docs.microsoft.com/ja-jp/sql/relational-databases/statistics/view-statistics-properties?view=sql-server-ver15
  • 26.
    DROP/TRUNCATE が使えない場合、1 件単位のDELETE ではなく、DELETE 対象キーのみの テーブルをロードし、そのテーブルとジョインして一括削除を行う データの削除は、まとめて行う 26 注意点 • DELETE に限らず、INSERT/UPDATE も 1 件単位の DML を繰り返し行うのではなく、処理をまとめて実行すること • Synapse SQL は、大量処理、大容量のスキャンが超高速である為、その特性を生かす処理を行う --------------------------------------------- -- まとめて削除 --------------------------------------------- --// 削除対象キーテーブルとジョインして、一括削除 DELETE t1 FROM dbo.T1 t1 INNER JOIN dbo.deleteKeysForT1 tg on t1.key1 = tg.key1
  • 27.
    ユーザー定義関数 (UDF) は、なるべく作成せず、特に大規模なテーブルを対象としたクエリには 利用しない ユーザー定義関数(UDF) は、なるべく使わない 27 注意点 • UDF は、並列処理を阻害する場合があり、性能に甚大な影響を与えることがある • 極力、組み込み関数の組み合わせで対応する
  • 28.
    クエリで条件比較やジョインを使う場合、UNICODE 型 (NCHAR/NVARCHAR)と非 UNICODE 型 (CHAR/VARCHAR) を混在させない 条件比較/結合でUNICODE 型と非 UNICODE 型を混在させない 28 注意点 • A (NVARCHAR) = B (VARCHAR) で比較/結合した場合、B は UNICODE に変換される為、性能に大きな影響が出る • JDBC Driver を経由したパラメータ化文字列は既定では UNICODE で送信される • 文字列は UNICODE 型を基本にしておく
  • 29.
    T-SQL では、複数のクエリを一つのバッチとして実行できる為、無理してサブクエリ化したような クエリは、ステップ分けした方が大幅に性能向上できる場合がある (例: Exadata40分 / Synapse SQL 当初 60分超 ⇒ 3.5分) T-SQL のメリットを最大化する 29 -------------------------------------------------------------------------- -- Query-1 の結果が1件 ★インメモリ -------------------------------------------------------------------------- --// 個別変数 DECLARE @DeviceId NCHAR(10) DECLARE @Temperature INT --// Query-1 SELECT TOP 1 @DeviceId = DeviceId, @Temperature = Temperature FROM dbo.asalog ORDER BY Temperature DESC; --// Query-2 SELECT a.*, @Temperature Temperature FROM dbo.asalog a WHERE a.DeviceId = @DeviceId; -------------------------------------------------------------------------- -- Query-1 の結果が小規模 (~数万件) ★インメモリ -------------------------------------------------------------------------- --// テーブル変数 DECLARE @tableVal TABLE ( DeviceId NCHAR(10), Temperature INT ) --// Query-1 INSERT INTO @tableVal SELECT TOP 1000 * FROM dbo.asalog ORDER BY Temperature DESC; --// Query-2 SELECT a.*, t.Temperature FROM dbo.asalog a INNER JOIN @tableVal t ON a.DeviceId = t.DeviceId; -------------------------------------------------------------------------- -- Query-1 の結果が中規模 (~数十万件) ★インメモリ -- CTE (Common Table Expression) の利用 -------------------------------------------------------------------------- --// CTE (Common Table Expression) WITH table_cte (DeviceId, Temperature) AS ( --// Query-1 SELECT TOP 100000 * FROM dbo.asalog ORDER BY Temperature DESC ) --// Query-2 SELECT a.*, t.Temperature FROM dbo.asalog a INNER JOIN table_cte t ON a.DeviceId = t.DeviceId; -------------------------------------------------------------------------- -- Query-1 の結果が大規模 (数百万件以上) ★一時テーブル on tempDB -- SQLDB BC/Hyperscale, Synapse SQL の場合、tempDB は NVMe SSD 上なので高速 -------------------------------------------------------------------------- --// 一時テーブル削除 IF OBJECT_ID(N'tempdb..#table1',N'U') IS NOT NULL DROP TABLE #table1; --// Query-1 to 一時テーブル SELECT TOP 2000000 * INTO #table1 FROM dbo.asalog ORDER BY Temperature DESC; --// Query-2 SELECT a.*, t.Temperature FROM dbo.asalog a INNER JOIN #table1 t ON a.DeviceId = t.DeviceId;
  • 30.
    ⚫ UPDATE よりも、DELETE& INSERT の方が高速 ⚫ MERGE 文が利用できるようになった (2020/09/23) その他、DML 処理の Tips 30 ※参照:https://docs.microsoft.com/ja-jp/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15
  • 31.
    Synapse Analytics 専用SQL Pool パフォーマンスチューニング
  • 32.
    チェック対象:1 分集計とした以下のメトリクスをチェックし、定常的に負荷が高い場合、DWU 追加を検討 •CPU used percentage 最大値 • Memory used percentage 最大値 • Local tempDB used percentage 最大値 (ソート, データ移動, Polybase によるロード, 一時テーブルで利用) • Adaptive cache hit percentage 平均値 (クエリ実行時に列ストアデータが NVMe SSD に載っている割合) ⇒ 80% 以上が目安 • Workload group active queries 合計 • Workload group queued queries 合計 ⇒ 定常的にキュー待ちが大量に起きていないか キャパシティが足りているかどうかをチェック 32
  • 33.
    チェック対象:以下クエリ実行時の [COMPRESSED_rowgroup_rows_XXX] 列の値は、104万行に近いほど品質が良い 問題の原因:データロード時のリソースクラス or ワークロード グループの REQUEST_MIN_RESOURCE_GRANT_PERCENT の値が小さ過ぎる 列ストア セグメントの品質を疑う 33 ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-index#optimizing-clustered-columnstore-indexes ---------------------------------------------------------------------------------- -- CCI セグメント品質のチェック (簡易版) ---------------------------------------------------------------------------------- -- [table_partition_count] パーティション数 -- [row_count_total] トータル行数 -- [COMPRESSED_rowgroup_rows] 圧縮済み行グループのトータル行数 -- [COMPRESSED_rowgroup_rows_MIN] 圧縮済み行グループ内の最小行数 -- [COMPRESSED_rowgroup_rows_MAX] 圧縮済み行グループ内の最大行数 -- [COMPRESSED_rowgroup_rows_AVG] 圧縮済み行グループ内の平均行数 -- [COMPRESSED_rowgroup_rows_DELETED] 行グループ内の論理削除された行数 ---------------------------------------------------------------------------------- SELECT s.name AS [schema_name] , t.name AS [table_name] , COUNT(DISTINCT rg.[partition_number]) AS [table_partition_count] , SUM(rg.[total_rows]) AS [row_count_total] , SUM(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE 0 END) AS [COMPRESSED_rowgroup_rows] , AVG(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_AVG] , MIN(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_MIN] , MAX(CASE WHEN rg.[State] = 3 THEN rg.[total_rows] ELSE NULL END) AS [COMPRESSED_rowgroup_rows_MAX] , SUM(CASE WHEN rg.[State] = 3 THEN rg.[deleted_rows] ELSE 0 END) AS [COMPRESSED_rowgroup_rows_DELETED] , SUM(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE 0 END) AS [OPEN_rowgroup_rows] , AVG(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_AVG] , MIN(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_MIN] , MAX(CASE WHEN rg.[State] = 1 THEN rg.[total_rows] ELSE NULL END) AS [OPEN_rowgroup_rows_MAX] , 'ALTER INDEX ALL ON ' + s.name + '.' + t.NAME + ' REBUILD;' AS [Rebuild_Index_SQL] FROM sys.[pdw_nodes_column_store_row_groups] rg JOIN sys.[pdw_nodes_tables] nt ON rg.[object_id] = nt.[object_id] AND rg.[pdw_node_id] = nt.[pdw_node_id] AND rg.[distribution_id] = nt.[distribution_id] JOIN sys.[pdw_table_mappings] mp ON nt.[name] = mp.[physical_name] JOIN sys.[tables] t ON mp.[object_id] = t.[object_id] JOIN sys.[schemas] s ON t.[schema_id] = s.[schema_id] --WHERE s.name = @schemaName AND t.name = @tableName GROUP BY s.[name], t.[name] ORDER BY s.[name], t.[name]
  • 34.
    チェック対象:以下クエリ実行時の [distribution_id] 列毎の[row_count] 列の値を見て、片寄りが無いかを確認 問題の原因:分散キーに設定した列が適切で無い (=カージナリティが低い or 値に片寄りがある) 可能性が高い ディストリビューションのデータの偏りを疑う 34 ※参照:https://docs.microsoft.com/ja-jp/azure/synapse-analytics/sql-data-warehouse/sql-data-warehouse-tables-distribute#determine-if-the-table-has-data-skew ★dbo.vTableSizes ビューは、参照先のリンクに定義がある ---------------------------------------------------------------------------------- -- 特定のノード/ディストリビューションにデータの偏りがないかのチェック ---------------------------------------------------------------------------------- -- 特定のテーブルについてノードにデータの片寄りが無いか DBCC PDW_SHOWSPACEUSED('schema_name.table_name'); -- ディストリビューションの 10% 以上の偏りを抽出 select two_part_name , pdw_node_id , pdw_node_type , distribution_id , dist_name,partition_nmbr , row_count , distribution_column , distribution_policy_name , index_type_desc from dbo.vTableSizes -- ★★ このビューは、参照先のリンクにスクリプトがある where two_part_name in ( select two_part_name from dbo.vTableSizes where row_count > 0 group by two_part_name having (max(row_count * 1.000) - min(row_count * 1.000))/max(row_count * 1.000) >= .10 ) order by two_part_name, distribution_id, row_count ;
  • 35.
    チェック対象:以下クエリ実行時の [operation_type] 列毎の[total_elapsed_time], [row_count] の値を見て、時間・件数が大きくないか確認 問題の原因: • BroadcastMoveOperation (全データを全ノードへ移動) :レプリケート テーブル適用について検討が必要 • ShuffleMoveOperation (ジョインに必要なデータの移動):ノード内でジョインが完結していない ⇒ 結合キー (列) を分散キーに出来ないか検討が必要 コンピュート ノード間でデータ移動が大量に発生していないか疑う 35 ※参照:https://docs.microsoft.com/ja-jp/sql/relational-databases/system-dynamic-management-views/sys-dm-pdw-request-steps-transact-sql?toc=/azure/synapse-analytics/sql-data- warehouse/toc.json&bc=/azure/synapse-analytics/sql-data-warehouse/breadcrumb/toc.json&view=azure-sqldw-latest -------------------------------------------- -- コンピュートノード間でのデータ移動を確認 -------------------------------------------- -- 完了した対象のクエリの QID を確認 SELECT * FROM sys.dm_pdw_exec_requests WHERE status in ('Completed','Failed','Cancelled') AND session_id <> session_id() ORDER BY submit_time DESC; -- 分散実行プランでデータ移動が大量に発生していないか確認 -- (BroadcastMoveOperation, ShuffleMoveOperation が対象) DECLARE @qid VARCHAR(20) = ’QIDxxxxxx’; SELECT * FROM sys.dm_pdw_request_steps WHERE request_id = @qid ORDER BY step_index;
  • 36.
    Shuffle Move の軽減方法 分散キーの見直し以外では、MaterializedView (MV) の利用が最も効果的 • オプティマイザーによって適切な MV が提案される • EXPLAIN WITH_RECOMMENDATIONS + SQL クエリによって、推奨される MV 作成スクリプトが提示される • EXPLAIN コマンドによって出力された実行プランを見ることで、Shuffle Move の有無、および、どのカラムで Shuffle しようとしているかを確 認することができる 例) 出力された実行プラン (XML) に、MV の候補が提示される 例) 出力された実行プラン (XML) に、Shuffle Move の情報を確認
  • 37.
    クエリに 「*」 指定していないかをチェック 37 チェック対象:SELECT* のように列を指定していないクエリかどうかを確認 問題の原因:列ストアで、列数の多いテーブルの場合、読み込むカタログ情報や I/O 対象となるセグメントの数が大量になるため