DQL と他のクエリ言語の比較¶
はじめに¶
DQL を迅速に理解し活用いただくため、ここでは 3 種類の一般的なクエリ言語(PromQL、LogQL、SQL)と比較します。
PromQL は Prometheus で時系列データをクエリするための言語です。LogQL は Grafana Loki 用のログクエリ言語であり、PromQL の構文構造を参考に設計されているため、PromQL と記法がよく似ています。SQL は日常的に最も広く使われている汎用クエリ言語であり、その構文構造は前二者とは大きく異なります(データベースによって多少の違いはありますが、ここではMySQL を例とします)。
注意
SQL は強力な追加・削除・検索・変更機能を持ちますが、ここでは比較のためにクエリ機能のみを取り出しています。
DQL は初期の構文構造が PromQL に似ていましたが、ビジネスの拡大に伴い、徐々に異なるクエリ機能を備えるようになりました。PromQL の基本的な構文構造を踏襲しつつ、SQL の構文構造や意味表現の一部を取り入れることで、より複雑なクエリを記述しやすくすることを目的としています。
以下では、各クエリ言語の違いを次の観点から説明します。
- 基本構文構造
- サポートされる一般的な定義済み関数
- 一般的なクエリの記法
基本構文構造¶
| クエリ言語 | 基本構造 |
|---|---|
| PromQL | 指标 {条件过滤列表} [起始时间:结束时间] |
| LogQL | {stream-selector} log-pipeline |
| SQL | SELECT <column-clause> <FROM-clause> <WHERE-clause> <GROUP-BY-clause> ... |
| DQL | namespace::指标集:(column-clause) [time-range-clause] { WHERE-clause } GROUP-BY-clause ORDER-BY-clause |
PromQL¶
Prometheus では、関連するメトリクスは個別の形式で編成されています。クエリでは、対象のメトリクスを直接検索できます。例:
ここでは、メトリクス http_requests_total を検索し、ラベル条件(environment と method)を指定してデータをフィルタリングしています。
注意
PromQL では、このラベル条件を Label Matchers と呼びます。これは簡単に言うと、WHERE 条件によるフィルタリングと考えることができます。
LogQL¶
名前の通り、LogQL は主にログ内容のクエリに使用されます。例:
{container="query-frontend", namespace="loki-dev"}
|= "metrics.go"
| logfmt
| duration > 10s and throughput_mb < 500
ここで、{...} 内の部分は、LogQL では Stream Selector と呼ばれ、データのクエリ範囲を指定するものです(SQL の FROM ... 部分に類似)。後半部分は Log Pipeline と呼ばれ、主にログ情報の抽出とフィルタリングを処理します。
このことから、LogQL の {...} は PromQL の Label Matchers と同様に、WHERE 条件によるフィルタリングと考えることができます。
SQL¶
最もよく知られているクエリ言語で、上記の 2 つの効果を実現する場合、簡単に翻訳すると次のようになります(ストレージ構造が異なるため、ここではおおまかな意味のみを示します)。
SELECT * FROM `loki-dev`
WHERE container="query-frontend" AND
duration > 10s AND
throughput_mb < 500
DQL¶
DQL は本質的にクエリトランスレータであり、そのバックエンドはデータの保存や編成を直接管理しません。そのため、理論的には任意のタイプのストレージエンジンをサポートできます。例えば、情報データストレージ(MySQL/Oracle/ES/Redis など)、ファイルストレージ(HBASE/S3/OSS など)です。現在、DQL は主に以下の種類のデータのクエリに使用されています。
- 時系列データ
- ログデータ
- オブジェクトデータ
- アプリケーションパフォーマンスモニタリング(APM)データ
- リアルユーザーモニタリング(RUM)データ
- キーイベントデータ
- ...
例:
ここで、metric は時系列データのクエリを指定し(MySQL の DB と考えてよい)、cpu はその中のメジャーメントの 1 つ(MySQL のテーブルに類似)であり、その中の 2 つのフィールド usage_system と usage_user を指定して検索します。次に、{...} の中はフィルタ条件を示し、最後に [...] はクエリの時間範囲(一昨日から昨日までの間で、1 時間の集約間隔)を示します。
その他の例:
# K8s の pod オブジェクトをクエリ(object)
object::kubelet_pod:(name, age) { cpu_usage > 30.0 } [10m] BY namespace
# my_service というアプリケーションのログを検索(message フィールド)
logging::my_service:(message) [1d]
# アプリケーションパフォーマンスモニタリング(T は tracing)において、持続時間 > 1000us の span データを表示し、operation でグループ化
T::my_service { duration > 1000 } [10m] BY operation
横断比較¶
基本機能の比較¶
| クエリ言語 | 主な分野 | 時系列クエリ | ログクエリ | 時間範囲検索 | group by 集約 |
|---|---|---|---|---|---|
| PromQL | Prometheus メトリクスクエリ | サポート | 非サポート | サポート | サポート |
| LogQL | ログクエリ | ログからのメトリクス生成をサポート | サポート | サポート | サポート |
| SQL | 汎用クエリ言語 | 一部のデータベース で時系列ストレージをサポート |
不適切 | サポート | サポート |
| DQL | Guance全プラットフォームデータクエリ | サポート | サポート | サポート | サポート |
周辺ツールのサポート¶
| クエリ言語 | コメント方式 | HTTP API | Pipeline 抽出 | コマンドライン |
|---|---|---|---|---|
| PromQL | # 单行注释 |
サポート | 非サポート | promql-cli |
| LogQL | # 单行注释 |
サポート | サポート | logcli |
| SQL | -- 单行注释または /* 多行注释 */ |
非サポート | 非サポート | 各種 SQL クライアント(ここでは省略) |
| DQL | # 单行注释 |
サポート | 非サポート(DataKit 側で事前に抽出済み) | DataKit のインストール 後、クエリを実行 |
データ処理関数のサポート状況¶
一般的なクエリ文の記法比較¶
通常のデータクエリとフィルタリング¶
# LogQL
{ cluster="ops-tools1", namespace="dev", job="query-frontend"}
|= "metrics.go"
!="out of order"
| logfmt
| duration > 30s or status_code!="200"
# PromQL(PromQL は一般的な意味での OR フィルタリングをサポートしていない可能性があります)
http_requests_total{ cluster='ops-tools1', job!='query=frontend', duration > 30s }
# SQL
SELECT * FROM dev
WHERE cluster='ops-tools' AND
job='query=frontend' AND
(duration > 30000000000 OR stataus_code != 200)
# DQL:構文構造からわかるように、DQL の意味論的な構成は SQL に近いです
L::dev {
cluster='ops-tools',
job='query=frontend',
message != match("out of order")
(duraton > 30s OR stataus_code != 200) # DQL はネスト構造のフィルタリングをサポート
}
以下は各種 DQL 文の記法の列挙です。
# where-clause は AND で連結できます。AND は `,' と意味的に同等です
L::dev {
cluster='ops-tools' AND
job='query=frontend' AND
message != match("out of order") AND
(duraton > 30s OR stataus_code != 200)}
# AS エイリアス/中国語変数をサポート
metric::cpu:(usage_system AS システム使用量, usage_user AS ユーザー使用量)
# where-clause は array-list IN フィルタリングをサポート
L::dev {
cluster='ops-tools' AND
job IN [ 'query=frontend', 'query=backend'] AND
message != match("out of order") AND
(duraton > 30s OR stataus_code != 200)
}
# base64 値の受け渡しをサポート:複雑な文字列(複数行など)の場合、面倒なエスケープを回避
T::dev {
cluster='ops-tools' AND
resourec IN [
'some-raw-string', # 通常の文字列
b64'c2VsZWN0ICoKZnJvbSBhYmMKd2hlcmUgeCA+IDAK' # base64 文字列
]
}
集約を含むクエリとフィルタリング¶
# LogQL
sum by (org_id) ({source="ops-tools",container="app-dev"} |= "metrics.go" | logfmt | unwrap bytes_processed [1m])
# PromQL
histogram_quantile(0.9, sum by (job, le) (rate(http_request_duration_seconds_bucket[10m])))
# DQL(注意:ops-tools の両側には `` を付ける必要があります。付けないと減算式として解釈されます)
L::`ops-tools`:(bytes_processed) {filename = "metrics.go", container="app-dev"} [2m] BY sum(orig_id)
データ状況の参照¶
# LogQL/PromQL では同様のクエリ機能は見つかりませんでした
# MySQL
show tables;
show databases;
# DQL
show_measurement() # 時系列メジャーメント一覧の表示
show_object_source() # オブジェクト分類一覧の表示
show_rum_source() # RUM データ分類一覧の表示
show_logging_source() # ログ分類一覧の表示
まとめ¶
以上、いくつかの一般的なクエリ言語について基本的な紹介を行いました。各言語には特定の適用分野があり、機能も大きく異なります。DQL の設計思想はハイブリッドストレージのクエリソリューションを提供することであり、これが他の言語と本質的に異なる点です。DQL は独自のストレージエンジンを持たないものの、その拡張性は他の言語をはるかに上回り、ハイブリッドストレージクエリという位置づけに合致しています。
現在、DQL は積極的に開発・改良が進められており、機能とパフォーマンスにはまだ大きな改善の余地があります。Guance では、すべてのデータクエリに DQL が全面的に適用されており、その機能、パフォーマンス、安定性は長期間の検証を経ています。Guance 製品の継続的な反復に伴い、DQL も製品や開発者のニーズに応えるべく、進化を続けていきます。