すべてのプロダクト
Search
ドキュメントセンター

Lindorm:列指向データへのアクセス

最終更新日:Mar 29, 2026

Lindorm 列指向ストレージは、データを列単位で格納および処理するカラムナ分散ストレージサービスです。行指向ストレージと比較して、クエリ応答時間を短縮し、I/O リソースを節約します。Lindorm コンピュートエンジンを使用して、名前空間とテーブルの作成、データの読み書き、ファイルのコンパクション、階層化ストレージの設定を行います。

概要

列指向ストレージは、車両インターネット(IoV)、モノのインターネット(IoT)、注文、およびログなどのシナリオにおいて、大量の半構造化データおよび構造化データに適しています。主な機能には以下が含まれます:

  • コンピューティングと分析:列指向データに対してインタラクティブな分析とオンラインコンピューティングを実行します。豊富なインデックス機能により、データの特定を高速化します。SQL ステートメントを使用して、大量のプライマリキーデータの追加、削除、変更、クエリを実行します。

  • 高スループット:水平スケーリングをサポートし、毎分テラバイト規模のデータを読み書きする能力を備えています。これは、迅速な IoV データインポート、モデル訓練データセットへのアクセス、大規模なレポート分析に適しています。

  • コスト効率:カラムナ高圧縮率アルゴリズム、高密度低コストメディア、コールド・ホットデータ分離、圧縮エンコーディング、コールドデータアーカイブストレージを使用して、ストレージコストを削減します。

  • 高可用性:イレイジャーコーディングを使用して、分散データセットの高可用性を確保し、単一障害点 (SPOF) のリスクを排除します。

  • オープンソース互換性:Iceberg API と互換性があり、Spark や Flink などのコンピュートエンジンに接続して、主流のデータエコシステムにシームレスに統合できます。

  • コールド・ホットデータ分離:ビジネス要件に基づいて、コールドデータとホットデータを異なるストレージメディアに格納することで、パフォーマンスのオーバーヘッドを削減し、ストレージコストを低減します。

前提条件

開始する前に、次のことを確認してください:

DDL

名前空間

名前空間 (データベース) を作成します。

USE lindorm_columnar;
CREATE NAMESPACE mydb;

名前空間 (データベース) を削除します。

USE lindorm_columnar;
DROP NAMESPACE mydb;

テーブル

テーブルを作成します。

テーブルの作成

次の例では、通常パーティションとバケットパーティションを持つプライマリキーテーブルを作成します:

USE lindorm_columnar;
CREATE TABLE mydb.mytable (
  id   INT    NOT NULL,
  city STRING NOT NULL,
  name STRING,
  score INT)
PARTITIONED BY (city, bucket(128, id))
TBLPROPERTIES (
  'primary-key' = 'id,city');

プライマリキーテーブルと非プライマリキーテーブルの比較

プライマリキーテーブル非プライマリキーテーブル
作成方法'primary-key'TBLPROPERTIES'primary-key'TBLPROPERTIES
データの一意性プライマリキーは一意です。重複した書き込みは既存のデータを上書きします一意性は保証されません。重複した行が存在する可能性があります
パーティショニング必須です。パーティション式のフィールドはプライマリキーフィールドである必要があります。最終レベルのパーティションはバケットパーティションである必要があります必須ではありません
サポートされるプライマリキーの型BOOLEAN、BYTE、SHORT、INT、LONG、FLOAT、DOUBLE、STRING、BINARY該当なし

パーティション式

PARTITIONED BY を使用して、データがパーティション間でどのように分散されるかを指定します。構文は次のとおりです:

PARTITIONED BY ([regular partition expression, ...] {bucket(bucketNum, bucketCol)})

次の表に、利用可能なパーティション変換関数を示します:

関数説明サポートされる型注意事項
bucket(N, col)列の値をハッシュ化して、データを N 個のシャードに分散しますBOOLEAN、BYTE、SHORT、INT、LONG、FLOAT、DOUBLE、STRING、BINARYbucketNum は書き込みとスキャンの同時実行数に直接影響します。プライマリキーテーブルの場合、最終レベルのパーティションはバケットパーティションである必要があります
col_name (ID)個別の値ごとに 1 つの物理パーティションを作成します任意日付、都市、性別などの集中した値を使用します。タイムスタンプのような離散値は、過剰なメタデータを生成するため避けてください

`bucketNum` のサイジング:テーブルを作成する前に合計データ量を評価し、各バケットパーティションが 50~512 MB のデータを保持するように bucketNum を選択します。バケットインデックスは bucket_index = hash(bucketCol) % bucketNum として計算されます。

データスキューの回避bucketCol の値が離散的であることを確認してください。

バケットのみのパーティションの例

例 1:単一列のプライマリキー、バケットパーティションのみ:

USE lindorm_columnar;
CREATE TABLE mydb.mytable (
  id    INT    NOT NULL,
  city  STRING,
  name  STRING,
  score DOUBLE)
PARTITIONED BY (bucket(1024, id))
TBLPROPERTIES (
  'primary-key' = 'id');

例 2:複合プライマリキー、バケットパーティションのみ:

USE lindorm_columnar;
CREATE TABLE mydb.mytable (
  id        INT  NOT NULL,
  timestamp LONG NOT NULL,
  city      STRING,
  name      STRING,
  score     DOUBLE)
PARTITIONED BY (bucket(512, timestamp))
TBLPROPERTIES (
  'primary-key' = 'id,timestamp');

通常パーティション + バケットパーティションの例

例 1:バケット付きの日付ベースの通常パーティション:

USE lindorm_columnar;
CREATE TABLE mydb.mytable (
  id    INT    NOT NULL,
  year  STRING NOT NULL,
  month STRING NOT NULL,
  day   STRING NOT NULL,
  city  STRING,
  name  STRING,
  score DOUBLE)
PARTITIONED BY (year, month, day, bucket(1024, id))
TBLPROPERTIES (
  'primary-key' = 'id,year,month,day');

例 2:バケット付きの複数列の通常パーティション:

USE lindorm_columnar;
CREATE TABLE mydb.mytable (
  id    INT    NOT NULL,
  date  STRING NOT NULL,
  city  STRING NOT NULL,
  name  STRING,
  score DOUBLE)
PARTITIONED BY (date, city, bucket(1024, id))
TBLPROPERTIES (
  'primary-key' = 'id,date,city');

現在の名前空間内のテーブルを表示します。

USE lindorm_columnar;
USE mydb;
SHOW TABLES;

既存のテーブルを表示します。

次の SQL ステートメントを実行して、テーブルスキーマを表示できます。

USE lindorm_columnar;
SHOW CREATE TABLE mydb.mytable;
DESC mydb.mytable;

特定のテーブルを削除します。

USE lindorm_columnar;
-- テーブルを削除しますが、データファイルは保持します。
DROP TABLE mydb.mytable;
-- テーブルとすべてのデータファイルを削除します。
DROP TABLE mydb.mytable PURGE;

テーブル内のデータをクリアします。

USE lindorm_columnar;
TRUNCATE TABLE mydb.mytable;

パーティション

パーティションを削除します。

DELETE FROMWHERE 句を使用してパーティションを削除します:

USE lindorm_columnar;
DELETE FROM mydb.mytable WHERE city = 'beijing';

DML

テーブル

テーブルにデータを挿入します。

  • 例 1:

    USE lindorm_columnar;
    INSERT INTO mydb.mytable VALUES (0, 'beijing', 'zhang3', 99);
  • 例 2:

    USE lindorm_columnar;
    INSERT INTO mydb.mytable SELECT id, city, name, score FROM another_table;

テーブル内のデータをクエリします。

  • 例 1:

    USE lindorm_columnar;
    SELECT * FROM mydb.mytable WHERE id = 0;
  • 例 2:

    USE lindorm_columnar;
    SELECT count(1), sum(score) FROM mydb.mytable WHERE city = 'beijing';

パーティション管理

時間の経過とともに、増分書き込みによって多数の小規模ファイルが生成されます。これらのファイルをより大きなファイルにコンパクションすることで、データとメタデータの冗長性が減り、クエリパフォーマンスが向上します。rewrite_data_files または rewrite_manifest を使用してコンパクションをトリガーします。

重要

どちらのコマンドもデータベースリソースを消費します。オフピーク時間に実行してください。

テーブル内のすべてのファイルをコンパクションします:

USE lindorm_columnar;
CALL lindorm_columnar.system.rewrite_data_files(table => 'mydb.mytable');

特定のパーティション内のファイルをコンパクションします:

USE lindorm_columnar;
CALL lindorm_columnar.system.rewrite_data_files(table => 'mydb.mytable', where => 'city=\"beijing\"');

テーブルマニフェストを再書き込みします:

USE lindorm_columnar;
CALL lindorm_columnar.system.rewrite_manifest('mydb.mytable');

完全なコマンドリファレンスについては、「rewrite_data_files」および「rewrite_manifest」をご参照ください。

ホットデータおよびコールドデータのストレージ

Lindorm は、3レベル (L1、L2、L3) のコールド・ホットデータ分離をサポートしています。頻繁にアクセスされるデータは高性能ストレージに保持され、古いデータは自動的に低コストのストレージに移動されます。データレイクサービスは非同期にダンプを処理します。このプロセス中もクエリは利用可能ですが、アクセスパフォーマンスはストレージ階層によって異なります。

重要

列指向データのコールド・ホット自動変換を有効にするには、Lindorm のテクニカルサポート (DingTalk ID: s0s3eg3) にご連絡ください。

コールド・ホット分離ポリシーは、時間パーティションにのみ基づいています。

CHS パラメーター

テーブルを作成または変更する際に、TBLPROPERTIES でコールド/ホットストレージ (CHS) 属性を設定します。

パラメーター説明フォーマットデフォルト
CHSデータがストレージレベル間を移動するタイミングを決定する時間しきい値 (秒単位)。値が 1 つの場合は L1/L2 の分割。値が 2 つ (num0, num1、ただし num0 < num1) の場合は L1/L2/L3 の分割。長整数、単位:秒
CHS_L1L1 (ホット) 階層のストレージタイプ'CHS_L1'='storagetype=<storage type>'CAPACITY_CLOUD_STORAGE
CHS_L2L2 階層のストレージタイプ。CHS が設定されている場合に必須です。CHS_L1 と同じフォーマットとして CHS_L1
CHS_L3L3 (最もコールドな) 階層のストレージタイプ。CHS に 2 つの値が設定されている場合に必須です。形式はCHS_L1
CHS_EXPCHS しきい値と比較するために、時間パーティションフィールドからデータ時間を抽出する式。toSec(col0, pattern0, col1, pattern1, ...)

サポートされるストレージタイプ

クラウドストレージの場合:CAPACITY_CLOUD_STORAGE (デフォルト)、STANDARD_CLOUD_STORAGEPERFORMANCE_CLOUD_STORAGECLOUD_ARCHIVE_STORAGE

アーカイブストレージ (CLOUD_ARCHIVE_STORAGE) は内部プレビュー段階です。有効にするには、Lindorm のテクニカルサポート (DingTalk ID: s0s3eg3) にご連絡ください。

ローカルディスクの場合:CAPACITY_CLOUD_STORAGE (デフォルト)、LOCAL_SSD_STORAGELOCAL_HDD_STORAGELOCAL_EBS_STORAGE

`CHS_EXP` パターントークン

パターントークン意味
yyyy
MM
dd
HH
mm

toSec() 関数は、一致するパーティションの最大データ時間を計算します。たとえば、パーティション year=2023, month=10, day=2 の場合:

  • toSec(year, yyyy)2023-12-31 23:59:59 を返します

  • toSec(year, yyyy, month, MM)2023-10-31 23:59:59 を返します

  • toSec(year, yyyy, month, MM, day, dd)2023-10-02 23:59:59 を返します

単一の結合された日付フィールド、たとえば date=2023-10-02 の場合:

  • toSec(date, yyyy-MM-dd)2023-10-02 23:59:59 を返します

例 1:1 か月 (2,592,000 秒) より古いデータを容量ストレージ (L2) に移動します:

CREATE TABLE table0 (col0 INT, year STRING, month STRING, day STRING)
PARTITIONED BY (year, month)
TBLPROPERTIES (
  'CHS'    = '2592000',
  'CHS_L2' = 'storagetype=CAPACITY_CLOUD_STORAGE',
  'CHS_EXP'= 'toSec(year,yyyy,month,MM,day,dd)'
);

例 2table0 のポリシーを更新します。1 か月より古いデータを容量ストレージに移動し、3 か月 (5,184,000 秒) より古いデータをアーカイブストレージに移動します:

ALTER TABLE table0
SET TBLPROPERTIES (
  'CHS'    = '2592000,5184000',
  'CHS_L2' = 'storagetype=CAPACITY_CLOUD_STORAGE',
  'CHS_L3' = 'storagetype=CLOUD_ARCHIVE_STORAGE',
  'CHS_EXP'= 'toSec(year,yyyy,month,MM,day,dd)'
);

例 3:単一の dt パーティションフィールド (フォーマット:yyyy/MM/dd、例:2020/12/1) を持つテーブルを作成します。1 か月より古いデータを容量ストレージに移動し、3 か月より古いデータをアーカイブストレージに移動します:

CREATE TABLE table1 (col0 INT, dt STRING)
PARTITIONED BY (dt)
TBLPROPERTIES (
  'CHS'    = '2592000,5184000',
  'CHS_L2' = 'storagetype=CAPACITY_CLOUD_STORAGE',
  'CHS_L3' = 'storagetype=CLOUD_ARCHIVE_STORAGE',
  'CHS_EXP'= 'toSec(dt,yyyy/MM/dd)'
);

注意事項

  • テーブルの作成時に CHS を設定するか、後で ALTER TABLE ... SET TBLPROPERTIES を使用して更新します。

  • CHS が正しく設定されていない場合、テーブルは正常に作成または更新されますが、データはストレージ階層間で自動的に移動されません。

  • ダンプは非同期で実行されます。このプロセス中もデータはアクセス可能ですが、アクセスパフォーマンスはストレージ階層によって異なる場合があります。

  • コールド・ホット分離は、時間ベースのパーティションでのみサポートされます。

ベストプラクティス

ポイントクエリのためのプライマリキーの指定

プライマリキールックアップは最速のクエリパスです。大規模なテーブルでは、最高のパフォーマンスを得るために、プライマリキーを指定し、狭いキー範囲内でクエリを実行してください。

サンプルテーブル:

USE lindorm_columnar;
CREATE TABLE orders (
  o_orderkey      INT    NOT NULL,
  o_custkey       INT,
  o_orderstatus   STRING,
  o_totalprice    DOUBLE,
  o_orderdate     STRING,
  o_orderpriority STRING,
  o_clerk         STRING,
  o_shippriority  INT,
  o_comment       STRING)
PARTITIONED BY (bucket(1024, o_orderkey))
TBLPROPERTIES (
  'primary-key' = 'o_orderkey');

ポイントルックアップ:

USE lindorm_columnar;
SELECT * FROM orders WHERE o_orderkey = 18394;

範囲スキャン (狭い範囲の方がパフォーマンスが向上します):

USE lindorm_columnar;
SELECT count(*) FROM orders WHERE o_orderkey > 100000 AND o_orderkey < 200000;

データの分離のためのパーティションの追加

列指向ストレージエンジン内のパーティションは物理的に分離されています。パーティションキーでフィルター処理するクエリは、関連のないパーティションを完全にスキップします。

日付パーティションを持つサンプルテーブル:

USE lindorm_columnar;
CREATE TABLE orders (
  o_orderkey      INT    NOT NULL,
  o_custkey       INT,
  o_orderstatus   STRING,
  o_totalprice    DOUBLE,
  o_orderdate     STRING  NOT NULL,
  o_orderpriority STRING,
  o_clerk         STRING,
  o_shippriority  INT,
  o_comment       STRING)
PARTITIONED BY (o_orderdate, bucket(1024, o_orderkey))
TBLPROPERTIES (
  'primary-key' = 'o_orderdate,o_orderkey');

1 日分のデータをクエリします:

USE lindorm_columnar;
SELECT o_orderdate, count(*) FROM orders WHERE o_orderdate = '2022-01-01' GROUP BY o_orderdate;

日付範囲をクエリします:

USE lindorm_columnar;
SELECT o_orderdate, count(*)
FROM orders
WHERE o_orderdate >= '2022-01-01' AND o_orderdate <= '2022-01-07'
GROUP BY o_orderdate;

データコンパクションによるスキャンパフォーマンスの向上

rewrite_data_files によるコンパクション後、データは各パーティション内でプライマリキーによってソートされ、スキャンパフォーマンスが大幅に向上します。コンパクションされたデータのみをクエリし、増分書き込みをスキップするには、read.scan-major-rewritten-files-onlytrue に設定します。

サンプルテーブル:

CREATE TABLE mydb.mytable (
  id    INT    NOT NULL,
  city  STRING NOT NULL,
  name  STRING,
  score INT)
PARTITIONED BY (city, bucket(4, id))
TBLPROPERTIES (
  'primary-key' = 'id,city');

テーブル全体をコンパクションします:

CALL lindorm_columnar.system.rewrite_data_files(table => 'mydb.mytable');

特定のパーティションをコンパクションします:

CALL lindorm_columnar.system.rewrite_data_files(table => 'mydb.mytable', where => 'city=\"beijing\"');

クエリをコンパクションされたデータのみに制限します:

ALTER TABLE mydb.mytable SET TBLPROPERTIES ('read.scan-major-rewritten-files-only' = true);
動作
trueコンパクションされたデータのみをクエリします。増分データは除外されます
false (デフォルト)増分書き込みを含むすべてのデータをクエリします

ソートキーによる非プライマリキーのクエリの高速化

コンパクション後、データはプライマリキーによってソートされます。非プライマリキー列に対するクエリを高速化するには、ソートキーを指定してからデータを再コンパクションします。

重要

ソートキーを指定した後、高速化のパフォーマンスを確保するためにパーティション内のデータを再書き込みする必要があります。再書き込みされたデータのみがクエリ可能で、増分データはクエリできません。

サンプル表:

USE lindorm_columnar;
CREATE TABLE orders (
  o_orderkey      INT    NOT NULL,
  o_custkey       INT,
  o_orderstatus   STRING,
  o_totalprice    DOUBLE,
  o_orderdate     STRING,
  o_orderpriority STRING,
  o_clerk         STRING,
  o_shippriority  INT,
  o_comment       STRING)
PARTITIONED BY (bucket(1024, o_orderkey))
TBLPROPERTIES (
  'primary-key'                          = 'o_orderkey',
  'read.scan-major-rewritten-files-only' = 'true');

ソートキーを設定する:

ALTER TABLE orders WRITE ORDERED BY o_shippriority, o_totalprice;

ソート順を適用するには、[Compact]:

CALL lindorm_columnar.system.rewrite_data_files(table => 'orders');

ソートキーを使用したクエリ:

USE lindorm_columnar;
SELECT count(*) FROM orders WHERE o_shippriority = 0;
USE lindorm_columnar;
SELECT count(*) FROM orders WHERE o_shippriority = 0 AND o_totalprice > 999.9;