mcpField
C
clickhouse-best-practices

clickhouse-best-practices

github.com/langfuseデータ・データベース36.7k39 回インストール今日更新
リポジトリ

clickhouse-best-practices について

スキーマ、クエリ、データ挿入を確認する開発者向けの ClickHouse ガイドスキルです。適用ルールを優先し、回答で参照元を示します。

主な機能

  1. 01スキーマ・クエリ・挿入の28ルール
  2. 02優先順位に沿ったルール確認と引用
  3. 03スキーマとマイグレーションの手順
  4. 04クエリと挿入のチェックリスト

活用シーン

  1. 01ClickHouse のテーブルスキーマとマイグレーションの確認
  2. 02クエリと JOIN 戦略の最適化
  3. 03挿入や変更のパターンの評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/langfuse/langfuse --skill clickhouse-best-practices

インストール後、Claude Code で/clickhouse-best-practicesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
rules/
_sections.md
_template.md
insert-async-small-batches.md
insert-batch-size.md
insert-format-native.md
insert-mutation-avoid-delete.md
insert-mutation-avoid-update.md
insert-optimize-avoid-final.md
query-index-skipping-indices.md
query-join-choose-algorithm.md
query-join-consider-alternatives.md
query-join-filter-before.md
query-join-null-handling.md
query-join-use-any.md
query-mv-incremental.md
query-mv-refreshable.md
schema-json-when-to-use.md
schema-partition-lifecycle.md
schema-partition-low-cardinality.md
schema-partition-query-tradeoffs.md
schema-partition-start-without.md
schema-pk-cardinality-order.md
schema-pk-filter-on-orderby.md
schema-pk-plan-before-creation.md
schema-pk-prioritize-filters.md
schema-types-avoid-nullable.md
schema-types-enum.md
schema-types-lowcardinality.md
schema-types-minimize-bitwidth.md

詳細

ClickHouse のベストプラクティス

スキーマ設計、クエリ最適化、データ取り込みに関する ClickHouse の包括的なガイダンスです。影響度の高い順に優先順位付けされた、3 つの主なカテゴリ(スキーマ、クエリ、挿入)にわたる 28 のルールが含まれています。

公式ドキュメント: ClickHouse のベストプラクティス

重要:このスキルの適用方法

ClickHouse に関する質問に回答する前に、次の優先順位に従ってください。

  1. rules/ ディレクトリで該当するルールを確認します
  2. ルールがある場合: そのルールを適用し、「rule-name によると…」のように回答内で引用します
  3. ルールがない場合: LLM の ClickHouse に関する知識を使用するか、ドキュメントを検索します
  4. 確信が持てない場合: 最新のベストプラクティスをウェブ検索します
  5. 必ず出典を引用します: ルール名、「一般的な ClickHouse のガイダンス」、または URL

ルールを優先する理由: ClickHouse には、一般的なデータベースの直感では誤解を招く可能性のある、列指向ストレージ、疎インデックス、マージツリーの仕組みなど、固有の動作があります。ルールには、検証済みの ClickHouse 固有のガイダンスがまとめられています。

Langfuse 固有のルール

  • events テーブルに対するクエリには、 packages/shared/src/server/queries/clickhouse-sql/event-query-builder.ts を使用してください。クエリビルダーで表現できないことを確認してからでなければ、 events の SQL を手書きしないでください。
  • events テーブルでは FINAL を使用しないでください。このテーブルは FINAL が不要な設計になっており、このキーワードはパフォーマンスを低下させます。
  • ClickHouse クエリのアトリビューションは、 packages/shared/src/server/clickhouse/queryTags.ts の JSON として system.query_log.log_comment に保存されます。 JSONExtractString(log_comment, 'surface')、 JSONExtractString(log_comment, 'route')、および JSONExtractString(log_comment, 'projectId') で解析してください。 surface の既知の値は trpc、publicapi、worker、mcp、および unknown です。ClickhouseWriter による挿入では、 projectId = "MULTI_PROJECT" が使用されます。
  • クエリのアトリビューションは、OpenTelemetry の baggage を通じて伝播します。 エントリーポイントでは、 packages/shared/src/server/headerPropagation.ts の contextWithLangfuseProps(...) を呼び出し、ClickHouse の surface、 任意の route、および任意の projectId を設定します。その後、 ClickHouse のリポジトリレイヤーが baggage を normalizeClickHouseQueryTags(...) で読み取り、log_comment に書き込みます。 すべてのリポジトリ呼び出しにタグを渡すのではなく、エントリーポイントで アトリビューションを設定することを優先してください。
  • packages/shared/clickhouse/migrations/canonical/** は、クラスター構成と 非クラスター構成のインストール向けにレンダリングされる、唯一の正規テンプレート ツリーです。クラスターに対応するすべての DDL の位置に {CLICKHOUSE_CLUSTER_CLAUSE} を配置してください。 {CLICKHOUSE_REPLICATION_PREFIX} は、モードによって意図的に異なるエンジンに 限って使用してください。どちらのモードでも意図的に非レプリケーションのままにする テーブルもあります。
  • 新しい正規マイグレーション内のすべてのメタデータ ALTER (ADD/DROP/MODIFY COLUMN、ADD/DROP INDEX)には {CLICKHOUSE_CLUSTERED_ONLY: SETTINGS alter_sync = 2} を含め、 ミューテーションを作成するすべての ALTER(MATERIALIZE …、UPDATE、 DELETE)には {CLICKHOUSE_CLUSTERED_ONLY: SETTINGS mutations_sync = 2} を 含める必要があります。ALTER が 1 つだけ含まれるファイルにも適用されます。 競合はファイル内ではなく、マイグレーションファイル間で発生するためです。 alter_sync のデフォルトは 1 なので、開始レプリカが Keeper 内のテーブルの メタデータバージョンを更新すると、ステートメントはすぐに返ります。その後、 golang-migrate は直ちに次のファイルを開き、その最初のテーブルへの ALTER が、 まだ古いバージョンのレプリカに到達する可能性があります。ClickHouse はその ステートメントをキューに入れることを拒否し、レプリカのメタデータバージョンが 共通メタデータバージョンより古いため、code 517 で実行全体を中止します。 mutations_sync は alter_sync の代わりにはならない点に注意してください。 前者はミューテーションの完了タイミングを制御するもので、メタデータの伝播は制御 しません。レンダラーは、非クラスターの MergeTree マイグレーションではこれらの フラグメントを省略します。意図的にモードごとの差異を設ける場合に限り、 {CLICKHOUSE_UNCLUSTERED_ONLY:...} を使用してください。既存の出力を正規化する 目的で、すでにリリース済みのマイグレーションに同期設定を後付けしないでください。 履歴上の互換性テストでは、既存の出力が意図的に保護されています。
  • ClickHouse のマイグレーションでは、CREATE OR REPLACE VIEW(および CREATE OR REPLACE TABLE/EXCHANGE TABLES)を使用しないでください。 アトミックな置き換えには renameat2 のファイルシステムサポートが必要ですが、 NFS ベースのセルフホスト環境(例:AWS EFS 上の ClickHouse データ)にはそれが ありません。その場合、マイグレーションが失敗し、起動時にデプロイが中止されます (GitHub issue #14906)。通常のビューを再定義する場合は、同じマイグレーション ファイル内で 2 つのステートメントを使用してください。最初に DROP VIEW IF EXISTS <name> {CLICKHOUSE_CLUSTER_CLAUSE}; を実行し、次に CREATE VIEW <name> {CLICKHOUSE_CLUSTER_CLAUSE} AS … を実行します。 マイグレーションランナーは x-multi-statement=true を渡し、golang-migrate は SQL を解析せずにファイルを ; で分割するため、コメントや文字列リテラルに セミコロンを含めないでください。ダーティ状態で一部だけ適用されたマイグレーションを migrate force の後に再実行できるよう、すべてのステートメントを冪等に保ってください (IF EXISTS/IF NOT EXISTS)。ビューの削除から作成までの間にビューを参照すると 一時的に失敗しますが、analytics_* エクスポートビューでは許容されます。そのため、 通常のビューをプロダクトのホットパスで使用しないでください。
  • ライブの挿入を受け取るソーステーブルを持つマテリアライズドビューを削除して 作り直さないでください。DROP と CREATE の間に挿入された行はすべて、 ターゲットテーブルに反映されないまま、永久に失われます。MV の SELECT を変更する 場合は、ALTER TABLE <mv> {CLICKHOUSE_CLUSTER_CLAUSE} MODIFY QUERY <select> を 使用してください。これにより、取り込みを中断せずに変換処理が切り替わります。 変更によって列が追加される場合は、まずターゲットテーブル(複数ある場合はすべて)に ALTER(ADD COLUMN IF NOT EXISTS …)を適用し、その後に MODIFY QUERY を 実行してください。ホストが、新しい MV クエリを、ターゲットレプリカに新しい列が 追加される前に適用しないよう、これらのターゲットテーブルへの ALTER には クラスター構成のみで使用する alter_sync テンプレートフラグメントを含める必要が あります。MODIFY QUERY を使用できるのは TO テーブル MV のみです (Langfuse の MV はすべて TO を使用します)。

レビュープロセス

スキーマレビュー(CREATE TABLE、ALTER TABLE)

次のルールファイルを順番に確認してください:

  1. rules/schema-pk-plan-before-creation.md - ORDER BY は変更できません
  2. rules/schema-pk-cardinality-order.md - キー内のカラム順序
  3. rules/schema-pk-prioritize-filters.md - フィルターカラムの追加
  4. rules/schema-types-native-types.md - 適切な型の選択
  5. rules/schema-types-minimize-bitwidth.md - 数値型のサイズ設定
  6. rules/schema-types-lowcardinality.md - LowCardinality の使用
  7. rules/schema-types-avoid-nullable.md - Nullable と DEFAULT の使い分け
  8. rules/schema-partition-low-cardinality.md - パーティション数の制限
  9. rules/schema-partition-lifecycle.md - パーティショニングの目的

次の点を確認してください:

  • PRIMARY KEY / ORDER BY のカラム順序(カーディナリティの低い順)
  • データ型が実際のデータ範囲に合っている
  • 適切な文字列カラムに LowCardinality が適用されている
  • パーティションキーのカーディナリティが制限されている(100~1,000 個の値)
  • ReplacingMergeTree を使用する場合、バージョンカラムがある
  • 新しい正規のマイグレーションに含まれるすべてのメタデータ ALTER に {CLICKHOUSE_CLUSTERED_ONLY: SETTINGS alter_sync = 2} が含まれている(ALTER が 1 つだけのファイルも対象です。問題が発生するのは次のマイグレーションファイルであるためです)。また、すべての MATERIALIZE … / UPDATE / DELETE に対応する mutations_sync フラグメントが含まれている。mutations_sync は alter_sync の代わりにはなりません。すでに配布済みのマイグレーション出力を標準化しないでください。両方のレンダリングモードで prepareMigrations.test.ts が成功する
  • マイグレーションに CREATE OR REPLACE VIEW/TABLE または EXCHANGE TABLES がない(NFS/EFS のセルフホストで問題が発生します)。通常のビューは、同じファイル内で DROP VIEW IF EXISTS と CREATE VIEW を使って再定義する
  • ソーステーブルへの INSERT が行われている間は、マテリアライズドビューを削除して再作成しない。SELECT の変更は、対象テーブルの ALTER の後に ALTER TABLE <mv> MODIFY QUERY で行う
クエリレビュー(SELECT、JOIN、集約)

次のルールファイルを確認してください:

  1. rules/query-join-choose-algorithm.md - アルゴリズムの選択
  2. rules/query-join-filter-before.md - JOIN 前のフィルタリング
  3. rules/query-join-use-any.md - ANY と通常の JOIN の使い分け
  4. rules/query-index-skipping-indices.md - セカンダリインデックスの使用
  5. rules/schema-pk-filter-on-orderby.md - ORDER BY とフィルターの整合性

次の点を確認してください:

  • フィルターで ORDER BY のプレフィックスカラムを使用している
  • JOIN では、結合後ではなく結合前にテーブルをフィルタリングしている
  • テーブルサイズに適した JOIN アルゴリズムを使用している
  • ORDER BY に含まれないフィルターカラムにスキップインデックスを使用している
INSERT 戦略レビュー(データの取り込み、更新、削除)

次のルールファイルを確認してください:

  1. rules/insert-batch-size.md - バッチサイズの要件
  2. rules/insert-mutation-avoid-update.md - UPDATE の代替手段
  3. rules/insert-mutation-avoid-delete.md - DELETE の代替手段
  4. rules/insert-async-small-batches.md - 非同期 INSERT の使用
  5. rules/insert-optimize-avoid-final.md - OPTIMIZE TABLE のリスク

次の点を確認してください:

  • INSERT 1 回あたりのバッチサイズが 10K~100K 行である
  • 頻繁な変更に ALTER TABLE UPDATE を使用していない
  • 更新パターンに ReplacingMergeTree または CollapsingMergeTree を使用している
  • 少量のバッチを高頻度で挿入する場合、非同期 INSERT が有効になっている

出力形式

次の形式で回答してください:

## Rules Checked
- `rule-name-1` - Compliant / Violation found
- `rule-name-2` - Compliant / Violation found
...

## Findings

### Violations
- **`rule-name`**: Description of the issue
  - Current: [what the code does]
  - Required: [what it should do]
  - Fix: [specific correction]

### Compliant
- `rule-name`: Brief note on why it's correct

## Recommendations
[Prioritized list of changes, citing rules]

優先度別のルールカテゴリ

優先度カテゴリ影響プレフィックスルール数
1主キーの選択重大schema-pk-4
2データ型の選択重大schema-types-5
3JOIN の最適化重大query-join-5
4挿入のバッチ処理重大insert-batch-1
5ミューテーションの回避重大insert-mutation-2
6パーティション戦略高schema-partition-4
7スキッピングインデックス高query-index-1
8マテリアライズドビュー高query-mv-2
9非同期挿入高insert-async-2
10OPTIMIZE の回避高insert-optimize-1
11JSON の使用中schema-json-1

クイックリファレンス

スキーマ設計 - 主キー(重大)
  • schema-pk-plan-before-creation - テーブル作成前に ORDER BY を計画します(変更不可)
  • schema-pk-cardinality-order - カーディナリティの低い列から高い列の順に並べます
  • schema-pk-prioritize-filters - 頻繁にフィルタリングされる列を含めます
  • schema-pk-filter-on-orderby - クエリのフィルターでは ORDER BY のプレフィックスを使用する必要があります
スキーマ設計 - データ型(重大)
  • schema-types-native-types - すべてに String を使わず、ネイティブ型を使用します
  • schema-types-minimize-bitwidth - 値に適合する最小の数値型を使用します
  • schema-types-lowcardinality - 一意な文字列が 10K 未満の場合は LowCardinality を使用します
  • schema-types-enum - 値の範囲が有限で検証が必要な場合は Enum を使用します
  • schema-types-avoid-nullable - Nullable を避け、代わりに DEFAULT を使用します
スキーマ設計 - パーティション(高)
  • schema-partition-low-cardinality - パーティション数を 100~1,000 に保ちます
  • schema-partition-lifecycle - クエリではなく、データのライフサイクル管理にパーティショニングを使用します
  • schema-partition-query-tradeoffs - パーティションプルーニングのトレードオフを理解します
  • schema-partition-start-without - パーティショニングなしで始めることを検討します
スキーマ設計 - JSON(中)
  • schema-json-when-to-use - 動的なスキーマには JSON を、既知のデータには型付き列を使用します
クエリ最適化 - JOIN(重大)
  • query-join-choose-algorithm - テーブルのサイズに基づいてアルゴリズムを選択します
  • query-join-use-any - 一致する行が 1 つだけ必要な場合は ANY JOIN を使用します
  • query-join-filter-before - JOIN の前にテーブルをフィルタリングします
  • query-join-consider-alternatives - JOIN の代わりに辞書や非正規化を検討します
  • query-join-null-handling - デフォルト値を使用するには join_use_nulls=0 を設定します
クエリ最適化 - インデックス(高)
  • query-index-skipping-indices - ORDER BY に含まれない列でのフィルターにはスキッピングインデックスを使用します
クエリ最適化 - マテリアライズドビュー(高)
  • query-mv-incremental - リアルタイム集計にはインクリメンタル MV を使用します
  • query-mv-refreshable - 複雑な JOIN には更新可能な MV を使用します
挿入戦略 - バッチ処理(重大)
  • insert-batch-size - INSERT ごとに 10K~100K 行をバッチ処理します
挿入戦略 - 非同期(高)
  • insert-async-small-batches - 頻度の高い小規模バッチには非同期挿入を使用します
  • insert-format-native - 最高のパフォーマンスを得るにはネイティブ形式を使用します
挿入戦略 - ミューテーション(重大)
  • insert-mutation-avoid-update - ALTER UPDATE の代わりに ReplacingMergeTree を使用します
  • insert-mutation-avoid-delete - 軽量 DELETE または DROP PARTITION を使用します
挿入戦略 - 最適化(高)
  • insert-optimize-avoid-final - バックグラウンドマージに任せます

適用するタイミング

以下に該当する場合に、このスキルが有効になります。

  • CREATE TABLE 文
  • ALTER TABLE による変更
  • ORDER BY または PRIMARY KEY に関する議論
  • データ型の選択に関する質問
  • 遅いクエリのトラブルシューティング
  • JOIN の最適化依頼
  • データ取り込みパイプラインの設計
  • 更新/削除戦略に関する質問
  • ReplacingMergeTree またはその他の特殊なエンジンの使用
  • パーティション戦略の決定

ルールファイルの構成

rules/ 内の各ルールファイルには、以下が含まれます。

  • YAML フロントマター:タイトル、影響レベル、タグ
  • 簡単な説明:このルールが重要な理由
  • 誤った例:アンチパターンとその説明
  • 正しい例:ベストプラクティスとその説明
  • 追加のコンテキスト:トレードオフ、適用するタイミング、参考資料

コメント