メインコンテンツまでスキップ
メインコンテンツまでスキップ

プロジェクション

プロジェクションは、クエリの実行を最適化する形式でデータを保存します。この機能は以下に役立ちます。

  • 主キーの一部でないカラムに対してクエリを実行する
  • カラムを事前に集約することで、計算とIOの両方を削減します

テーブルに対して1つ以上のプロジェクションを定義でき、クエリ分析時に、ユーザーが提供したクエリを変更することなく、スキャンするデータが最も少ないプロジェクションがClickHouseによって選択されます。

ディスク使用状況

プロジェクションは内部で新しい隠しテーブルを作成します。これは、より多くのIOとディスク上のスペースが必要になることを意味します。 例えば、プロジェクションに異なる主キーが定義されている場合、元のテーブルのすべてのデータが複製されます。

プロジェクションが内部でどのように機能するかについての詳細な技術情報は、この ページ で確認できます。

主キーを使用せずにフィルタリングの例

テーブルの作成:

CREATE TABLE visits_order
(
   `user_id` UInt64,
   `user_name` String,
   `pages_visited` Nullable(Float64),
   `user_agent` String
)
ENGINE = MergeTree()
PRIMARY KEY user_agent

ALTER TABLEを使用して、既存のテーブルにプロジェクションを追加することができます:

ALTER TABLE visits_order ADD PROJECTION user_name_projection (
SELECT
*
ORDER BY user_name
)

ALTER TABLE visits_order MATERIALIZE PROJECTION user_name_projection

データの挿入:

INSERT INTO visits_order SELECT
    number,
    'test',
    1.5 * (number / 2),
    'Android'
FROM numbers(1, 100);

プロジェクションを使用することで、元のテーブルでuser_namePRIMARY_KEYとして定義されていなくても、user_nameによるフィルタリングを迅速に行うことができます。 クエリ実行時にClickHouseは、プロジェクションを使用することで処理されるデータが少なくなると判断しました。なぜなら、データはuser_nameで順序付けられているからです。

SELECT
    *
FROM visits_order
WHERE user_name='test'
LIMIT 2

クエリがプロジェクションを使用しているかどうかを確認するには、system.query_logテーブルを確認できます。projectionsフィールドには、使用されているプロジェクションの名前が表示され、使用されていない場合は空になります:

SELECT query, projections FROM system.query_log WHERE query_id='<query_id>'

事前集約クエリの例

プロジェクションを持つテーブルの作成:

CREATE TABLE visits
(
   `user_id` UInt64,
   `user_name` String,
   `pages_visited` Nullable(Float64),
   `user_agent` String,
   PROJECTION projection_visits_by_user
   (
       SELECT
           user_agent,
           sum(pages_visited)
       GROUP BY user_id, user_agent
   )
)
ENGINE = MergeTree()
ORDER BY user_agent

データの挿入:

INSERT INTO visits SELECT
    number,
    'test',
    1.5 * (number / 2),
    'Android'
FROM numbers(1, 100);
INSERT INTO visits SELECT
    number,
    'test',
    1. * (number / 2),
   'IOS'
FROM numbers(100, 500);

最初のクエリをGROUP BYを使用してuser_agentフィールドに対して実行します。このクエリは、事前集約が一致しないため、定義されたプロジェクションを使用しません。

SELECT
    user_agent,
    count(DISTINCT user_id)
FROM visits
GROUP BY user_agent

プロジェクションを使用するには、事前集約およびGROUP BYフィールドの一部またはすべてを選択するクエリを実行することができます。

SELECT
    user_agent
FROM visits
WHERE user_id > 50 AND user_id < 150
GROUP BY user_agent
SELECT
    user_agent,
    sum(pages_visited)
FROM visits
GROUP BY user_agent

以前に述べたように、system.query_logテーブルを確認できます。projectionsフィールドには、使用されているプロジェクションの名前が表示され、使用されていない場合は空になります:

SELECT query, projections FROM system.query_log WHERE query_id='<query_id>'

_part_offsetフィールドを持つ通常のプロジェクション

_part_offsetフィールドを利用する通常のプロジェクションを持つテーブルの作成:

CREATE TABLE events
(
    `event_time` DateTime,
    `event_id` UInt64,
    `user_id` UInt64,
    `huge_string` String,
    PROJECTION order_by_user_id
    (
        SELECT
            _part_offset
        ORDER BY user_id
    )
)
ENGINE = MergeTree()
ORDER BY (event_id);

サンプルデータの挿入:

INSERT INTO events SELECT * FROM generateRandom() LIMIT 100000;

_part_offsetをセカンダリア索引として使用する

_part_offsetフィールドはマージや変異を通じて値を保持するため、セカンダリア索引として価値があります。これをクエリで利用できます。

SELECT
    count()
FROM events
WHERE _part_starting_offset + _part_offset IN (
    SELECT _part_starting_offset + _part_offset
    FROM events
    WHERE user_id = 42
)
SETTINGS enable_shared_storage_snapshot_in_query = 1

プロジェクションの操作

以下の操作が プロジェクション に対して可能です:

PROJECTIONを追加

ALTER TABLE [db.]name [ON CLUSTER cluster] ADD PROJECTION [IF NOT EXISTS] name ( SELECT <COLUMN LIST EXPR> [GROUP BY] [ORDER BY] ) - テーブルメタデータにプロジェクションの説明を追加します。

PROJECTIONを削除

ALTER TABLE [db.]name [ON CLUSTER cluster] DROP PROJECTION [IF EXISTS] name - テーブルメタデータからプロジェクションの説明を削除し、ディスクからプロジェクションファイルを削除します。ミューテーションとして実装されています。

PROJECTIONをマテリアライズ

ALTER TABLE [db.]table [ON CLUSTER cluster] MATERIALIZE PROJECTION [IF EXISTS] name [IN PARTITION partition_name] - クエリがpartition_nameにおいてプロジェクションnameを再構築します。ミューテーションとして実装されています。

PROJECTIONをクリア

ALTER TABLE [db.]table [ON CLUSTER cluster] CLEAR PROJECTION [IF EXISTS] name [IN PARTITION partition_name] - 説明を削除せずにディスクからプロジェクションファイルを削除します。ミューテーションとして実装されています。

コマンドADDDROPCLEARは、メタデータを変更するか、ファイルを削除するだけなので軽量です。

また、これらはレプリケーションされ、ClickHouse KeeperまたはZooKeeperを介してプロジェクションメタデータを同期します。

注記

プロジェクションの操作は、*MergeTreeエンジンを持つテーブルに対してのみサポートされています(レプリケートバリアントを含む)。