世界を動かす技術を、日本語で。

Show HN: SQL-tap – PostgreSQLおよびMySQL用リアルタイムSQLトラフィックビューワー

概要

sql-tap は、アプリケーションとデータベースの間に配置する リアルタイムSQLトラフィックビューアPostgreSQLMySQL のクエリをキャプチャし、 TUI(ターミナルUI) で表示。 アプリケーションコードの変更なしで、 EXPLAIN やトランザクションの確認が可能。 インストール方法やクイックスタート、主要な操作方法を解説。 MITライセンス で提供。

sql-tapとは

  • sql-tap は、SQLトラフィックを リアルタイムで可視化 するプロキシデーモン+TUIクライアント。
  • アプリケーションとデータベース( PostgreSQL または MySQL)の間に設置し、 全クエリをキャプチャ
  • インタラクティブなTUIで クエリ確認・トランザクション表示・EXPLAIN実行 が可能。
  • アプリケーション側の コード変更は不要、ポートを切り替えるだけで導入可能。
  • EXPLAINEXPLAIN ANALYZE もTUIから直接実行可能。

インストール方法

  • Homebrew
    • brew install --cask mickamy/tap/sql-tap
  • Go
    • go install github.com/mickamy/sql-tap@latest
    • go install github.com/mickamy/sql-tap/cmd/sql-tapd@latest
  • ソースからビルド
    • git clone https://github.com/mickamy/sql-tap.git
    • cd sql-tap
    • make install
  • Docker(PostgreSQL用)
    • FROM postgres:18-alpine
    • ADDコマンドでバイナリ取得・展開
    • ENTRYPOINTsql-tapd起動(ポート:5433→5432へ転送)
  • Docker(MySQL用)
    • FROM mysql:8
    • PostgreSQLと同様の手順(ポート:3307→3306へ転送)

クイックスタート

  • 1. プロキシデーモンの起動
    • PostgreSQLの場合
      • DATABASE_URL="postgres://user:pass@localhost:5432/db?sslmode=disable" sql-tapd --driver=postgres --listen=:5433 --upstream=localhost:5432
    • MySQLの場合
      • DATABASE_URL="user:pass@tcp(localhost:3306)/db" sql-tapd --driver=mysql --listen=:3307 --upstream=localhost:3306
  • 2. アプリケーションの接続先をプロキシポートへ変更
    • アプリケーションコードの修正不要
    • データベースのポートをプロキシのポート(例:5433や3307)に切り替え
  • 3. TUIの起動
    • sql-tap localhost:9091
    • リアルタイムで全クエリが表示

主なコマンド・オプション

  • sql-tapd(プロキシデーモン)
    • -driverpostgresまたはmysqlを指定(必須)
    • -listen:クライアントからの待受アドレス(必須)
    • -upstream:上流DBアドレス(必須)
    • -grpc:TUI用gRPCサーバーアドレス(デフォルト: :9091
    • -dsn-env:EXPLAIN用DSN格納環境変数(デフォルト: DATABASE_URL
    • -version:バージョン表示
    • EXPLAIN機能利用時はDATABASE_URLの設定が必要
  • sql-tap(TUIクライアント)
    • -version:バージョン表示
    • <addr>sql-tapdのgRPCアドレス(例:localhost:9091)

TUIのキーバインド

  • リストビュー
    • j / :下に移動
    • k / :上に移動
    • Ctrl+d / PgDn:半ページ下
    • Ctrl+u / PgUp:半ページ上
    • /:インクリメンタルサーチ
    • s:ソート切替(時系列/実行時間)
    • Enter:クエリ/トランザクション詳細
    • Space:トランザクション展開/折りたたみ
    • Esc:検索解除
    • x:EXPLAIN
    • X:EXPLAIN ANALYZE
    • e:クエリ編集+EXPLAIN
    • E:クエリ編集+EXPLAIN ANALYZE
    • a:アナリティクスビュー
    • c:クエリコピー
    • C:バインド済みクエリコピー
    • q:終了
  • 詳細ビュー・アナリティクスビュー・EXPLAINビューも同様に直感的なキーバインド

動作原理

  • sql-tapd はデータベースの ワイヤプロトコル (PostgreSQL/MySQL)を解析し、 クエリを透過的にインターセプト
  • プリペアドステートメントパラメータバインドトランザクション実行時間影響行数エラー などを追跡。
  • イベントは gRPC でTUIクライアントへ リアルタイム配信
  • アプリケーションコードの変更不要、ポートの切り替えのみで導入可能。

ライセンス

  • MITライセンス で提供。
  • 商用・個人利用問わず自由に使用可能。

sql-tapの特徴まとめ

  • 透過的なSQLプロキシ によるクエリキャプチャ
  • PostgreSQL/MySQL両対応
  • EXPLAINEXPLAIN ANALYZE の実行サポート
  • アプリケーションのコード変更不要
  • TUIによる直感的な操作性
  • 簡単な導入手順 と多様なインストール方法
  • MITライセンス による自由な利用

推奨ユースケース

  • SQLパフォーマンス解析
    • クエリの実行時間や頻度の可視化
  • トラブルシューティング
    • エラークエリや異常なトランザクションの特定
  • 開発・検証環境でのSQL監視
    • アプリケーションの動作確認やチューニング時に最適

参考リンク

  • GitHubリポジトリ: https://github.com/mickamy/sql-tap

Hackerたちの意見

これめっちゃいいね!個人的には、エージェントがデータベースで実行するクエリを調べる方が、コードをレビューするよりもコードの動きが理解しやすいと思う。試してみたけど、スムーズに動いたよ。データベースにエージェントを直接接続したくない人のために、同じ目的で使えるツールを作ったんだ。https://dbfor.dev これはPGLiteを埋め込んで、PGワイヤプロトコルを実装して、トラフィックビューア付きのクイックPGデータベースを立ち上げるためのものだよ。

私たちもadaptiveで似たようなことをやってるよ。[1] それに、プロキシにフロントエンドとバックエンドのユーザーを追加すれば、エージェントが実際のデータベースユーザーやパスワードを取得することはないよ。使い捨てにしたり、必要な時だけ使うこともできるし。従来はデータベースのアクティビティモニタリングが主流だったけど、エージェントの登場でまた注目されると思う。[1] https://adaptive.live

これがMySQLの一般ログを必要に応じて有効にするよりもいい選択肢だってどう説明できるの?

そう、これが最初の質問だった。なんでこのデータを調べる必要があるのか、問題の原因を探してるからかもしれないけど、他に理由はあるの?

それか、Postgresで log_statement = 'all' を使うのもありだね。

DBサーバー自体にアクセスする必要はないし(例えば、クエリログを読むために)、接続先のホストを変えるだけで全てできるよ。

笑、そうだね。まあ、真面目なアプリケーションだと、クエリがめっちゃ速く飛び交って、仮のテーブルを作ったり、いろんなカラムを引っ張ってきたり、即座に解釈するのが難しいことをやったりするよね。特に、自分が書いたわけじゃないソフトウェアだと。ログをオンにする方が役立つことが多いと思う。金融系のアプリの内部動作を理解するためにそれをやったことがあるよ。

pgTAP [0] が存在していて、これとは関係ないから、名前を変えることを考えた方がいいかも。[0]: https://pgtap.org/

なんでプロキシが必要なの?ネットワークからクエリを引き出せばいいじゃん。すべてのクエリに遅延を追加してるよ! https://github.com/circonus-labs/wirelatency

SSL暗号化された接続には対応してないけど、確かに遅延は増えるよね。

プロキシとパケットキャプチャの議論は、実際にはあまり意味がないかな。TLSが有効になった瞬間(常に有効にすべきだけど)、パケットキャプチャでは役に立つ情報が見えなくなる。eBPFは観測性には面白いけど、ネットワークやシステムコールレベルで動くから、実際のSQLレベルの検査やブロックをeBPFでやろうとすると、TCPストリームを再構成してPostgresのワイヤプロトコルをカーネル空間で解析しなきゃいけないから、実用的じゃないんだよね。GoでPostgresのワイヤプロトコルプロキシを作ってるけど、遅延の問題はみんなが最初に言うことなんだ。でも、それは心配するべきことじゃない。プロキシはマイクロ秒の遅延を追加するけど、クエリはミリ秒かかる。誰も気にしないよ。実際の難しい部分、つまり何週間もかかるのは、ワイヤプロトコルを正しく実装すること。みんな簡単なクエリメッセージから始めて、80%終わったと思うんだけど、拡張クエリプロトコル(Parse/Bind/Execute)やプリペアドステートメント、COPY、通知にぶつかって、シンプルな道がPostgresの実際の動作の20%に過ぎないことに気づくんだよね。でも、それを乗り越えれば、モニタリングはほぼ副産物になる。すでにすべてのクエリを解析しているから、フィルタリングしたり、ポリシーを強制したり、テナントレベルのアイソレーションを行ったり、認証情報をローテーションしたりできる。これは受動的アプローチでは根本的に不可能なことなんだ。

試してみたけど、問題なく動いたよ。めっちゃ好き!WordPressサイトで試したんだけど、一回のリクエストで何百ものSQLクエリが表示されてる(だからそのWordPressサイトが遅いのかも笑)。ここで見たいのは、- 実行時間や順番でのソート機能。遅いクエリが見えるように。- 検索/フィルター機能。- pgup/pgdownキーでのスクロールをもっと速く。- 同じクエリがどれくらい実行されたかの情報。コードをチェックして、クエリを最適化できるかもしれない。

個人的には、観測性のための透過的プロキシは最良のパターンじゃないと思う。経験から言うと、Envoy用のPostgresプラグインを開発したし、StackGresなどでも同じ理由で使ってる。問題は主に二つある。* 遅延。そう、そう、そう、プロキシは「マイクロ秒」を追加するけど、クエリは「ミリ秒」かかる。それは本当だけど、物語の一部に過ぎない。追加のホップがある。TCPレイヤーが二重に通過する。もしホップがローカル(例えば、StackGresでやってるサイドカー)なら、デプロイや管理が複雑になる(自動化で解決したけど、追加の問題だった)。リソースも消費する。ネットワークホップなら、ミリ秒が追加されて、マイクロ秒じゃなくなる。* パフォーマンス。機能するPGワイヤプロキシを書くのはそれほど難しくない(簡単でもないけど)。でも、高負荷のシナリオでうまく動かすのは非常に難しい。見たプロキシのほとんどは、中程度から高いパフォーマンスで崩れちゃう。じゃあ、解決策は?Postgresの拡張モデルでメトリクスをキャプチャすること(eBPFも試したけど、カーネルとユーザースペースのコンテキストスイッチが多すぎるから、拡張で同じことができるならそっちの方がいい)、そしてOTELのような標準化されたプロトコルでメトリクスをプッシュする小さなサイドカー。

メトリクスをキャプチャするためのPostgresの拡張モデル(eBPFも試したけど、カーネルとユーザースペースのコンテキストスイッチが多すぎるから、拡張で同じことができるならそっちの方がいい)、そしてOTELのような標準化されたプロトコルでメトリクスをプッシュする小さなサイドカー。拡張モデルは素晴らしいけど、既存のPostgresプロバイダー(RDSやAuroraなど)とは互換性がない。もしそのような拡張が全てのプロバイダーにサポートされるほど標準化されれば理想的だと思う。はっきり言うと、pg_stat_statementsのことを言ってるわけじゃなくて、実際のクエリをリアルタイムでプッシュする拡張のこと。 > ネットワークホップなら、ミリ秒が追加されて、マイクロ秒じゃなくなる。接続確立時間のことを言ってるの?それともクエリ遅延のこと?後者は通常、1ミリ秒未満であるべきだと思う。

あなたが言ってることはわかる。こういうプロキシだと、遅延やパフォーマンスが少しでも影響を受けるから、実際のDB環境では重要だよね。でも、そんなにプロキシを悪く言う必要はないと思う。常に本番環境でインラインで動かす必要はないし、驚くほど有用な結果を得られるんだ。確かに、たくさんの本番環境のインサイトソリューションがあるけど、最近のスタックは複雑すぎることもあって、デバッグしているページがDBとどうやって話しているかを素早く把握できるのは非常に有用だと思う。だから、こういうソリューションのアイデアが好きなんだ。もちろん、mytopやpgtopみたいなものだけど、異なるレイヤーで現代的なインターフェースを提供しようとしている。自分には役に立ちそうに思える。

https://www.envoyproxy.io/docs/envoy/latest/configuration/li... https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overv...

開発者用のデフォルトのdocker-composeにこれを入れて、マイクロサービスでプロジェクトに取り組むときに、何かおかしいことがあったらSQLクエリをすぐに確認できるようにしてもいい?そのシナリオでは、このUIはどう機能するんだろう。Reactフロントエンドの方がその目的に合ってる気がする。

sqltapとは混同しないでね。あれもクエリのデバッグにめっちゃ便利だよ: https://github.com/inconshreveable/sqltap