デジタル化の加速に伴い、地球規模のデータ量が飛躍的に増加しており、データベース システムのパフォーマンスに大きな課題をもたらしています。データベース管理システムの主要なテクノロジであるオプティマイザは、データベースのパフォーマンスと効率に重要な影響を及ぼします。ユーザーのクエリ リクエストを分析および最適化して効率的な実行プランを生成し、クエリ結果を迅速に返します。ただし、最適化の決定が異なると、同じ SQL ステートメントでも桁違いのパフォーマンスの違いが生じる可能性があります。データ サイズとクエリの複雑さの増加に伴い、オプティマイザーの継続的な開発と革新は、データベース システムの継続的なパフォーマンス向上にとって重要な方向性となり、データベース システムの最も強力な競争力の 1 つでもあります。
クラウドネイティブおよび分散シナリオ向けに、クラウドネイティブの仮想データ ウェアハウスである PieCloudDB Database は、新世代のオプティマイザー「Daqi」を設計および構築しました。名前はゲーム「レッド・デッド・リデンプション」のNPCキャラクターからインスピレーションを得たもので、彼のキャッチフレーズ「I have a plan」はオプティマイザーの機能にぴったりです。
オプティマイザー「Daqi」は、PieCloudDB に多くの最適化機能を実装しており、高品質のクエリ プランを生成することで、データベース システムの「シンクタンク」として機能し、クエリのパフォーマンスとユーザーの効率を確保します。「Daqi」は、クエリ ステートメントをインテリジェントに分析し、クエリ プランを最適化し、分散データ ストレージとコンピューティング機能を利用することにより、より高速かつ効率的なクエリ処理を実現します。
佗酒牌のマスコット「パイパイ」
1 集計操作と集計プッシュダウン
今回は「Daqi」の新機能「集める・倒す」について詳しく紹介していきます。最新のデータベース システムでは、集計操作 (Aggregate) は非常に一般的なタイプの操作です。集計操作により、複数行のデータを 1 行に結合し、それに対して統計、合計、平均の計算を実行できます。
従来のクエリ実行プロセスでは、通常、クエリ結果が返された後に集計操作が実行され、集計計算のためにすべてのデータをクエリ エンジンに送信する必要があります。ただし、大規模なデータセットや複雑なクエリの場合、このアプローチはクエリのパフォーマンスの低下、高い計算負荷、高額な計算コストなどの問題を引き起こす可能性があります。
これらの問題を解決するために、PieCloudDB オプティマイザー「Daqi」は集計プッシュダウン機能 (Aggregate Pushdown) を作成し、テストの結果、多くのシナリオで集計プッシュダウン機能は 100 倍、さらには 1000 倍のパフォーマンス向上を達成しました。
2 集合体プッシュダウンの原則
プッシュダウン集計は、集計操作をデータ ソースにプッシュダウンすることでデータ送信と処理のオーバーヘッドを削減し、クエリのパフォーマンスと効率を向上させるデータベース クエリ最適化テクノロジです。
集計プッシュダウンの実現原理は、クエリ実行プロセスのできるだけ早い段階で集計操作を実行し、処理のために集計操作をデータ ソースにプッシュダウンすることです。具体的には、クエリ プランが生成されると、オプティマイザは集計操作をデータ ソースにプッシュダウンして、データ ソースで集計計算を実行できるようにします。これにより、データ転送量が削減され、クエリ エンジンの負担が軽減され、データ ソースの計算能力をローカル集約に使用できます。
簡単な図を使用して、集約プッシュダウンの主な実装原理を説明してみましょう。
「集計プッシュダウン」の有無の比較
上図の左図は集計プッシュダウンなしの実行プロセス、右図は集計プッシュダウンありの実行プロセスです。左の図で集計プッシュダウンがない場合、テーブル T1 と T2 が最初に接続され、接続後のデータ セットに対して集計操作が完了します。
右図の集計プッシュダウンの場合、テーブル T1 と T2 で結合操作が実行される前に、テーブル T1 で集計操作が実行されます。このようにして、一部のシナリオでは、結合操作中にテーブル T1 に含まれるデータの量を大幅に削減できるため、クエリのパフォーマンスが大幅に向上します。クエリ効率を正確に向上させるために、上記 2 つの実行プランが「Daqi」で生成され、最終的にコスト モデルの見積もりに従ってコストが低い方の実行プランが選択されます。
接続に参加するテーブルの数が増えると、「Daqi」は集計操作を異なる接続層にプッシュダウンしようとし、コスト比較を通じて最適なプッシュダウン位置を選択します。
3 集約プッシュダウンのデモンストレーション例
次に、クエリの例を通じて集計プッシュダウンの効果を見てみましょう。まず、次のステートメントを使用してテスト テーブルを作成します。
CREATE TABLE t (x int , y int ); INSERT INTO t SELECT i % 30 , i % 30 FROMgenerate_series ( 1 , 10240 ) i; tを分析します 。
テストに使用したクエリは次のとおりです。
SELECT t1 .x、sum( t2 .y + t3 .y)、 count (*) FROM t t1 JOIN t t2 ON t1 .x = t2 .x JOIN t t3 ON t2 .x = t3 .x GROUP BY t1 .x ;
集計プッシュダウンがない場合、クエリ プランは次のようになります。
EXPLAIN (分析、コストオフ) SELECT t1.x、sum(t2.y + t3.y)、count(*) FROM t t1 JOIN t t2 ON t1.x = t2.x JOIN t t3 ON t2.x = t3 .x t1.x による グループ化 ; クエリプラン ------------------------------------------------ -------------------------------------------------- ------------------------- ギャザー モーション 3:1 (スライス 1; セグメント: 3) (実 時間=153884.859..274102.066 行=30 ループ= 1) -> HashAggregate (実際の 時間=274100.004..274100.011 行=12 ループ=1) グループ キー: t1.x ピーク メモリ使用量: 0 kB -> ハッシュ結合 (実際の 時間=38.717..100579.782 行=477571187 ループ=1) ハッシュ条件: (t1.x = t3.x) 追加テキスト: (seg0) ハッシュ チェーンの長さ 341.4 平均、342最大、131072 バケットのうち 12 個を使用します。 -> ハッシュ結合 (実際の 時間=2.088..429.203 行=1398787 ループ=1) ハッシュ条件: (t1.x = t2.x) 追加テキスト: (seg0) ハッシュ チェーンの長さ 平均 341.4、最大 342、131072 のうち 12 を使用バケツ。 -> モーションを再分配 3:3 (スライス 2; セグメント: 3) (実 時間)=0.044..4.590 行=4097 ループ=1) ハッシュ キー: t1.x -> t t1 でのシーケンス スキャン (実際の 時間=1.382..32.683 行=3496 ループ=1) -> ハッシュ (実際の 時間=1.760.. 1.761 行=4097 ループ=1) バケット: 131072 バッチ: 1 メモリ使用量: 1185kB -> モーションの再配布 3:3 (スライス 3; セグメント: 3) (実際の 時間=0.049..0.922 行=4097 ループ=1) ハッシュ キー: t2.x -> t t2 のシーケンス スキャン (実際の 時間=1.628..32.837 行=3496 ループ=1) -> ハッシュ (実際の 時間=36.153..36.153 行=4097 ループ=1) バケット: 131072 バッチ: 1 メモリ使用量: 1185kB -> モーションの再配布 3:3 (スライス 4; セグメント: 3) (実際の 時間= 3.918..35.169 行= 4097 ループ= 1) ハッシュ キー: t3.x -> t t3 でのシーケンス スキャン (実際 時間=1.380..30.316 行=3496 ループ=1) 計画時間: 8.810 ミリ秒 (スライス 0) 実行プログラム メモリ: 257K バイト。 (slice1) Executor メモリ: 平均 2484K バイト x 3 ワーカー、最大 2570K バイト (seg0)。Work_mem: 最大 1185K バイト (slice2) Executor メモリ: 平均 32840K バイト x 3 ワーカー、最大 32841K バイト (seg0)。 (slice3) Executor メモリ: 平均 32860K バイト x 3 ワーカー、最大 32860K バイト (seg0)。 (slice4) Executor メモリ: 平均 32860K バイト x 3 ワーカー、最大 32860K バイト (seg0)。 使用メモリ: 128000kB オプティマイザー: Postgres クエリ オプティマイザー 実行時間: 274130.589 ミリ秒 (32 行)
集計プッシュダウンがある場合、クエリ プランは次のようになります。
EXPLAIN (分析、コストオフ) SELECT t1.x、sum(t2.y + t3.y)、count(*) FROM t t1 JOIN t t2 ON t1.x = t2.x JOIN t t3 ON t2.x = t3 .x t1.x による グループ化 ; クエリプラン ------------------------------------------------ -------------------------------------------------- -------------------------------------------------- ------ モーション 3:1 の収集 (スライス 1; セグメント: 3) (実 時間=835.755..836.406 行=30 ループ=1) -> GroupAggregate の最終処理 (実 時間=834.227..835.432 行=12 ループ= 1) グループ キー: t1.x -> ソート (実際の 時間=834.031..834.441 行=4097 ループ=1) ソートキー: t1.x ソート方法: クイックソート メモリ: 1266kB -> モーションを再配布 3:3 (スライス 2; セグメント: 3) ) (実際の 時間=812.139..830.706 行=4097 ループ=1) ハッシュ キー: t1.x -> ハッシュ結合 (実際の 時間=810.536..828.097 行=3496 ループ=1) ハッシュ条件: (t1.x = t2 。バツ) 追加テキスト: (seg0) ハッシュ チェーンの長さは平均 1.0、最大 1.0、131072 バケットのうち 30 個を使用。 -> t t1 のシーケンス スキャン (実際の 時間=1.689..16.674 行=3496 ループ=1) -> ハッシュ (実際の 時間=808.497..808.498 行=30 ループ=1) バケット: 131072 バッチ: 1 メモリ使用量: 1026kB -> ブロードキャスト モーション 3:3 (スライス 3; セグメント: 3) (実 時間=461.065..808.466 行=30 ループ)=1) -> 部分ハッシュ集約 (実際の 時間=810.026..810.033 行=12 ループ=1) グループ キー: t2.x ピーク メモリ使用量: 0 kB -> ハッシュ結合 (実際の 時間=28.070..331.181 行=1398787 ループ=1) ハッシュ条件: (t2.x = t3.x) 行) 追加テキスト: (seg0) ハッシュ チェーンの長さは平均 341.4、最大 342、262144 バケットのうち 12 個を使用。 -> モーションを再配布 3:3 (スライス 4; セグメント: 3) (実際の 時間=0.040..1.270 =4097 ループ=1) ハッシュ キー: t2.x -> t t2 でのシーケンス スキャン (実際の 時間=1.449..19.963 行) =3496 ループ=1) -> ハッシュ (実際の 時間=27.834..27.835 行=4097 ループ=1) バケット: 262144 バッチ: 1 メモリ使用量: 2209kB -> モーション 3:3 の再配布 (スライス 5; セグメント: 3) (実際の 時間=3.836..27.025 行=4097 ループ=1) ハッシュ キー: t3.x -> t t3 のシーケンス スキャン (実際の 時間=1.537..23.654 行=3496) ループ=1) 計画時間: 14.425 ミリ秒 (スライス 0) エグゼキューター メモリ: 328K バイト (スライス 1) エグゼキューター メモリ: 平均 408K バイト x 3 ワーカー、最大 514K バイト (seg0)。Work_mem: 最大 450K バイト。 (slice2) Executor メモリ: 平均 33951K バイト x 3 ワーカー、最大 33952K バイト (seg0)。Work_mem: 最大 1026K バイト (slice3) Executor メモリ: 平均 2298K バイト x 3 ワーカー、最大 2341K バイト (seg0)。Work_mem: 最大 2209K バイト (slice4) Executor メモリ: 平均 32860K バイト x 3 ワーカー、最大 32860K バイト (seg0)。 (slice5) エグゼキューター メモリ: 平均 32860K バイト x 3 ワーカー、最大 32860K バイト (seg0)。 使用メモリ: 128000kB オプティマイザー: Postgres クエリ オプティマイザー 実行時間: 865.305 ミリ秒 (39 行)
2 つのクエリ プランを比較すると、集計プッシュダウンがない場合 (クエリ プラン 1)、最初にすべての接続操作を完了する必要があり、その後、接続されたデータ セットに対して集計操作が実行されることがわかります。集約プッシュダウン (クエリ プラン 2) は、集約操作を最適な接続層にプッシュダウンすることで、後続の接続操作のデータ量を削減し、パフォーマンスを大幅に向上させることができます。
この例では、「Daqi」は、t2 と t3 の間の接続後、t1 との接続の前に集約操作をプッシュダウンします。これら 2 つの実行時間を比較すると、実行時間が以前の 274130.589 ミリ秒から 865.305 ミリ秒に短縮され、300 倍以上のパフォーマンス向上が達成されていることがわかります。データ量がさらに増加するか、クエリに含まれるテーブルの数がさらに増加すると、集計プッシュダウンのパフォーマンスの向上がより顕著になります。
集計なしのプッシュダウンと集計ありのプッシュダウンの比較
PieCloudDB の新しいオプティマイザー「Daqi」は、述語のプッシュダウン、サブクエリのサブ結合のプロモーション、外部結合の削除など、一連の包括的なロジック最適化機能をユーザーに提供します。オンライン分析処理 (OLAP) シナリオ用のデータベースとして、オプティマイザー「Daqi」は、集計およびプッシュダウン機能をサポートするだけでなく、さまざまな複雑なクエリのニーズを満たすデータ スキップや事前計算などの高度な機能も備えています。今後の記事では、より深く理解していただけるよう、これらの機能を 1 つずつ紹介していきます。乞うご期待!
Redis 7.2.0 がリリース、最も広範囲にわたるバージョンの 中国人プログラマーがギャンブル プログラムの作成を拒否、14 本の歯が抜かれ、全身の 88% が損傷、 Flutter 3.13 がリリース、 System Initiative はすべてのソフトウェアがリリースされると発表初の大 規模独立アプリ登場、Grace が「Doubao」に名前変更 Spring 6.1 は仮想スレッドと JDK 21 に対応 Linux タブレット StarLite 5: デフォルトの Ubuntu、12.5 インチ Chrome 116 正式リリース Red Hat デスクトップ再導入Linux開発、主要開発者が異動 Kubernetes 1.28正式リリース