この記事は、HUAWEICLOUDコミュニティ「HuaweiCloudGaussDB(for Influx)Revealing the Fifth Issue:Sub-Query of Best Practices」、作成者:GaussDBデータベースから共有されています。
「アラート!アラート!」。
「目覚ましは何?」眠りについたシャオ・ワンは、運用・保守の同僚からの電話で突然目が覚め、顔を驚かせた。
「クエリが遅い!顧客から障害が報告されました!急いで対処してください!」
Xiao Wangは、問題を見つけるために環境にリモート接続されたポータブルをすばやく開き、最終的に遅いクエリがサブクエリであることを発見しました。「いいえ、同じステートメントは昨日遅いクエリを報告しませんでしたか?」
しかし、シャオ・ワンはすぐにその理由を理解しました。この遅いクエリの問題は、サブクエリの内部クエリがデータを集約してから外部クエリに出力する可能性があることですが、集約がないため、データ量が多いと非常に遅くなります。
核心を見つけたXiaoWangは、最適化されたSQLステートメントを運用および保守の同僚を通じて顧客にすぐに渡し、アラームは最終的に解決されました。
「質問を整理する時が来たようです!」彼の明確な考えを利用して、XiaoWangはそれを整理し始めました...
0 1 サブクエリとは何ですか?
サブクエリは、別のクエリ内にネストされたクエリであり、通常、コードの柔軟性を高めるためにInfluxQL構文のfromステートメントに配置されます。サブクエリは主に次のカテゴリに分類されます。
スカラーサブクエリ(scalarsubquery):1行1列の値を返します
行サブクエリ(rowsubquery):返される結果セットは1行N列です
列サブクエリ(columnsubquery):返される結果セットはN行1列です
テーブルサブクエリ(tablesubquery):返される結果セットはN行N列です
たとえば、クエリステートメントでは次のようになります。
select first(sum_f1)/first(sum_f2) from (select sum(f1) as sum_f1 from mst), (select sum(f2) as sum_f2 from mst)
2つのサブクエリが使用されます。これらは、テーブルmstからそれぞれ2つの列f1とf2の合計を取得し、結果sum_f1とsum_f2を外部クエリステートメントの外部クエリのソースとして使用します。
GaussDB(Influxの場合)サブクエリの一般的な構文は、SELECT_clause FROM(SELECT_statement)[...]です。サブクエリを処理するロジックを次の図に示します。
システムは最初にサブクエリステートメントを処理し、サブクエリの結果は外部クエリのデータソースとしてキャッシュされます。最後に、外部クエリが処理され、結果が顧客に返されます。
02サブクエリ の使用シナリオ
サブクエリは、単純なクエリを処理できない場合、またはクエリのデータに基づいてさらに処理するために使用されます。たとえば、各グループの最小値の中で最大の3つを見つけるために使用されます。
SELECT top (v,3)
FROM (
SELECT min (value) AS v
FROM mst
GROUP BY tag1
)
サブクエリは柔軟性に優れていますが、原則としてサブクエリはお勧めしません。理由は非常に単純です。通常のクエリと比較して、サブクエリはより深い関数呼び出しとより大きなデータボリュームを持ち、より多くのリソースを消費し、レイテンシーを増加させます。
03ケース 分析
GaussDB(Influx用)を使用して開発する過程で、次のようなサブクエリでいくつかの問題に直面することがよくあります。
1.サブクエリはいつ使用しますか?
2.複雑なシナリオに直面した場合、それを解決するためにサブクエリに分解する方法は?
3.記述されたサブクエリは最適ですか?再度最適化できますか?
次に、特定のケースを組み合わせて、サブクエリと分析のアイデアを効率的に使用する方法を簡単に分析します。
HUAWEI CLOUDのユーザーは、GaussDB(Influx用)を使用して毎日約5億4000万ポイントを書き込み、タイムラインは100w以上です。ビジネス、時間とスペースのクエリ、リクエストの成功率のクエリ、topNのクエリ。
ケース分析と実践のためのサンプルデータとして、次の感度低下データを取ります。
-
ケース1サブクエリをいつ使用するか?
ユーザーは、時空間グループ化のサブクエリを使用し、時空間グループ化の結果を集約する外部クエリのソースとして使用します。クエリステートメントは次のとおりです。
SELECT SUM(req_nums)
FROM(
SELECT requestNum AS req_nums
FROM req_table
WHERE statement=’SUCCESS’ AND time >= 1629129600000000000
AND time<=1629129611000000000 )
WHERE time>=1629129600000000000 AND time<=1629129611000000000
AND req_nums < 50
GROUP BY time(1s), group
ORDER BY time ASC
結果として生じる問題:
ユーザーの使用シナリオでは、クエリサブクエリは条件付きフィルタリングと列名の変更のみを実装しているため、内部クエリはSELECT requestNum ASreq_nums+フィルタリングと同等です。非集計シナリオのクエリには大規模なものが必要です。取得する生データの量が多いため、クエリ速度が遅くなり、クエリ効率がユーザーの要件を満たしていません。
ソリューション:
クエリステートメントを分析すると、ユーザーの要求は、条件を満たすデータ(statement ='SUCCESS' AND requestNum <50)を時空間集約(GROUPBY TAG、time(5m))に集約することであることがわかります。クエリターゲットを明確にすると、より明確に記述できます。効率的なクエリステートメント:すべてのフィルター条件をまとめて、時空間集計を直接実行します。
文法の改善:
SELECT SUM(requestNum)
FORM req_table
WHERE statement=’SUCCESS’ AND requestNum < 50
AND time>=1629129600000000000 AND time<=1629129611000000000
GROUP BY time(1s), group
ORDER BY time ASC
-
ケース2サブクエリを使用して複雑な問題を解決する
ユーザーのビジネスシナリオでは、リクエストの成功率を計算する必要があります。つまり、データの特定の列がフィルター処理され、さまざまなフィルター条件に従ってカウントされ、最後に比率が計算されます。GaussDB(Influx用)はcase whenステートメントをサポートしていないため、異なるケースに応じて同じ列の異なるデータをフィルターで除外することは困難です。多くの開発者がそのような問題に遭遇したとき、彼らは何も知りません。
ソリューション:
ステップ1:サブクエリ+マルチテーブル機能を使用して、フィルター条件に従ってデータの同じ列を2つの列に変更します。
SELECT * FROM
(SELECT requestNum AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT requestNum AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
ステップ2:クエリされたデータをカウントします。
SELECT SUM(success_requestNum) AS total_success_reqNum, SUM(total_requestNum) AS total_requestNum
FROM
(SELECT requestNum AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT requestNum AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
GROUP BY time ASC
ステップ3:最終的な成功率のクエリステートメントを記述します。
SELECT SUM(success_requestNum)/SUM(total_requestNum) AS success_ratio
FROM
(SELECT requestNum AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT requestNum AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
GROUP BY time ASC
-
ケース3サブクエリステートメントを最適化する方法は?
ケース2に基づいて、成功率を見つける方法を取得しました。クエリステートメントは次のとおりです。
SELECT SUM(success_requestNum)/SUM(total_requestNum) AS success_ratio
FROM
(SELECT requestNum AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT requestNum AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
GROUP BY time ASC
結果として生じる問題:
クエリ時間が120秒を超えるユーザーが作成したクエリステートメントは、ビジネス要件を満たしていないため、さらに最適化する必要があります。
文法の改善:
上記のサブクエリの原則と解決策によれば、データ量を減らしてクエリを高速化するために、集約クエリをサブクエリ内に配置する必要があります。最適化されたクエリステートメントは次のとおりです。
SELECT SUM(success_requestNum)/SUM(total_requestNum) AS success_ratio
FROM
(SELECT SUM(requestNum) AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT SUM(requestNum) AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
GROUP BY time ASC
クエリ結果は同じです。
最適化効果:
最適化されていないクエリには126秒、最適化されたクエリには2.7秒かかり、パフォーマンスは47倍向上します。
*知らせ
SUM(success_requestNum)を使用する場合、SUM(total_requestNum)の目的はデータを整列させることです。SELECTsuccess_requestNum / total_requestNumを直接使用すると、データを同時に整列できないため、誤った結果になります。
SELECT *
FROM
(SELECT SUM(requestNum) AS success_requestNum FROM req_table WHERE statement=’SUCCESS’ AND time>=1629129600000000000 AND time<=1629129611000000000),
(SELECT SUM(requestNum) AS total_requestNum FROM req_table WHERE time>=1629129600000000000 AND time<=1629129611000000000)
GROUP BY time ASC
クエリの合計データ量は、クエリ速度と正の関係があります。データクエリ量が多いほど、クエリ速度は遅くなります。したがって、サブクエリまたは非サブクエリのクエリステートメントを記述している場合は、最初の原則として、クエリのデータ量を削減しようとします。つまり、集計クエリ(通常はデータ量を削減するクエリ)を可能な限りサブクエリ内に配置する必要があります。
04柔軟なサブクエリ と高性能
GaussDB(Influx用)は、柔軟なサブクエリ機能を提供するだけでなく、ベクトル化、メモリ再利用、およびその他のテクノロジーを使用してクエリ効率を継続的に改善し、大規模なデータシナリオでのユーザーのクエリパフォーマンス要件を満たします。
ベクトル化されたクエリ: GaussDB(Influx用)は、SIMD命令セットを使用して、データ処理の並列度を向上させます。同時に、ベクトル化されたデータモデルを使用すると、1回の反復でポイントのバッチを処理できるため、計算の反復回数が大幅に削減され、計算が高速化されます。
メモリの再利用:クエリプロセス中のGCによるメモリのリサイクルと割り当てが可能な限り削減され、要求されたメモリが個別に管理されるため、クエリプロセス中のメモリ拡張の問題が解決され、GCがクエリを頻繁に削減します。速度。
05まとめ_
GaussDB(Influx用)はサブクエリ機能をサポートしているため、問題を柔軟に処理でき、ユーザーの要件も高くなります。不当なサブクエリは、クエリの遅延やリソースの消費量が多いなどの問題を引き起こすことがよくあります。 GaussDB(Influx用)サブクエリを使用する場合は、次の点に注意する必要があります。
1.サブクエリに適用できるビジネスロジックを理解します。サブクエリは、クエリされたデータが2回(複数回)処理されるシナリオに適しています
。2。サブクエリを使用できないシナリオでは、サブクエリの使用を避けてください。 ;
3.使用する必要がありますサブクエリのシナリオでは、データ量を削減するクエリを可能な限りサブクエリに入れて、全体的なクエリデータ量を削減し、クエリを高速化します。
06終了_
この記事の著者:HUAWEICLOUDデータベースイノベーションラボとHUAWEICLOUD時空間データベースチームぜひご
参加ください。
クラウドデータベースイノベーションラボ(北京、成都)配信再開メール:[email protected]
HUAWEI CLOUD時空間データベースチーム(深セン、西安)配信再開メール:[email protected]