# Machbase DBMS マニュアル — 全文
> 公開中の Machbase DBMS 8.7.0 日本語ページをナビゲーション順にまとめた Markdown コーパスです。
- language: `ja`
- document_count: `242`
- document_index: https://docs.machbase.com/ja/llms-chunks.json
---
title: "Machbase DBMS マニュアル"
url: https://docs.machbase.com/ja/dbms/
language: ja
kind: section
---
# Machbase DBMS マニュアル
Machbase DBMS マニュアルへようこそ。本書は Machbase 8.7.0 を対象に、インストール、
テーブルタイプ別の利用方法、アプリケーション開発、運用、セキュリティ、リファレンスを説明します。
初めて利用する場合は、1章の SQL 演習を実行し、2章でデータモデルとストレージ・運用の原理を学びます。
システムを設計する場合は、4章のテーブル選択基準を確認してから、必要なテーブルの章に進んでください。
利用中の機能の正確な構文やサポート範囲は16章で確認できます。
## マニュアルの構成
| 章 | タイトル | 内容 |
|----|------|------|
| 1 | [はじめに](./getting-started/) | 概要、接続確認、クイックスタート、基本コマンド |
| 2 | [基本概念](./core-concepts/) | テーブルタイプ、時間モデル、ROLLUP、Retention Policy |
| 3 | [インストール・デプロイ・アップグレード](./installation-deployment-upgrade/) | 事前準備、Standard Edition、Cluster Edition、アップグレード |
| 4 | [テーブルタイプの選択とスキーマ設計](./data-modeling-table-design/) | タイプの選択、スキーマ、変更ポリシー、モデリングパターン |
| 5 | [TAG テーブルの利用](./tag-table-usage/) | TAG 構造、メタデータ、入力、クエリ、補正、運用 |
| 6 | [TAG テーブルの ROLLUP](./tag-rollup-usage/) | ROLLUP の設計、作成、クエリ、再構築、運用、性能チューニング |
| 7 | [LOG テーブルの利用](./log-table-usage/) | LOG 構造、入力、テキスト検索 |
| 8 | [TRANSACTION テーブルの利用](./rdb-table-usage/) | TRANSACTION スキーマ、DML、トランザクション、JOIN、バックアップ・リストア |
| 9 | [LOOKUP テーブルの利用](./lookup-table-usage/) | 参照データ、PRIMARY KEY、JSON、一般的な述語を使う DML、JOIN |
| 10 | [VOLATILE テーブルの利用](./volatile-table-usage/) | インメモリテーブル、UPSERT、状態キャッシュ、再起動とデータ消失 |
| 11 | [開発とアプリケーション連携](./development-tools-integration/) | 連携方式、共通概念、言語別 SDK/API |
| 12 | [性能チューニング](./performance-tuning/) | クエリ性能、取り込み性能、キャッシュ調整 |
| 13 | [運用・設定・復旧](./operations-configuration-recovery/) | サーバー管理、バックアップ、Cluster 運用 |
| 14 | [アカウント・権限・アクセス制御](./security-access-control/) | アカウント、権限、AUTH KEY、アクセス制御 |
| 15 | [トラブルシューティング](./troubleshooting/) | エラーの診断と解決 |
| 16 | [リファレンス](./reference/) | SQL 構文、関数、設定、システムカタログ |
---
title: "1. はじめに"
url: https://docs.machbase.com/ja/dbms/getting-started/
language: ja
kind: section
---
# 1. はじめに
この章は、データベースを初めて扱う方や、他の DBMS から Machbase を利用する方の出発点です。
Machbase DBMS 8.7.0 がどのようなデータをどう保存するかを確認し、1件のイベントの入力とクエリを通じて
基本的な SQL の流れを学びます。
概要はデータベースをインストールする前でも読めます。演習には、稼働中の DBMS サーバーと
接続ツール `machsql` が必要です。インストールと接続の準備は
[10分クイックスタート](./quick-start/)の前提条件で説明します。
## この章で学ぶこと
1. テーブル、行、列、SQL の役割を理解します。
2. 時間とともに蓄積する履歴と現在の状態を区別します。
3. 計測値、イベント、参照データに適した Machbase のテーブルタイプを確認します。
4. サーバーに接続し、LOG テーブルを作成してデータを入力・検索します。
5. イベント発生時刻とサーバー受信時刻の違いを確認し、次に読む文書を選びます。
## 読む順序
| 節 | 読んだ後にできること |
|---|---|
| [Machbase DBMS の概要](./overview/) | 時系列データベースの目的と各テーブルタイプの役割を説明できます。 |
| [10分クイックスタート](./quick-start/) | 接続、データの入力・クエリ、演習用テーブルの削除を実行できます。 |
| [基本コマンド早見表](./command-cheatsheet/) | シェルコマンドと SQL を区別し、よく使うコマンドを探せます。 |
| [次に読む文書の選択](./choose-next-doc/) | データや開発・運用作業に合った文書に進めます。 |
演習では、動作を確認しやすい少量の SQL `INSERT` を使用します。継続的に到着する大量データの
入力方式とエラー処理は、[データの入力とエクスポート](/ja/dbms/development-tools-integration/data-input-load-export/)
で続けて学べます。
---
title: "1.1 Machbase DBMS の概要"
url: https://docs.machbase.com/ja/dbms/getting-started/overview/
language: ja
kind: page
---
# 1.1 Machbase DBMS の概要
Machbase DBMS は、センサー計測値、設備イベント、アプリケーションログなど、時間とともに蓄積する
データを保存し、SQL で検索・分析する時系列データベースです。データの構造と変更・クエリ方式に
適したテーブルを選び、元の履歴と参照データを組み合わせて管理します。
## Machbase DBMS の紹介
### データベースと SQL の役割
データベースはアプリケーションが収集したデータを一定の構造で保存し、複数の処理で再利用できるようにします。
DBMS は、データの読み書き要求、ユーザー権限、保存領域を管理するソフトウェアです。
テーブルは、同じ構造を持つレコードの集まりです。行は1件のイベントや計測を表し、列は時刻、
設備名、計測値などの項目を表します。列には数値、文字列、日時などのデータ型を指定します。
このように定義した構造をスキーマと呼びます。
例えば、温度履歴は次のように表せます。以下の時刻と値は概念説明用です。
| 計測対象 | 計測時刻 | 温度 |
|---|---|---:|
| 設備 A の温度センサー | 09:00:00 | 23.1 |
| 設備 A の温度センサー | 09:00:01 | 23.5 |
| 設備 B の温度センサー | 09:00:01 | 18.0 |
SQL はデータを操作する言語です。`CREATE` でテーブルを作成し、`INSERT` で行を追加し、
`SELECT` で必要な行と列を読み出します。`WHERE` は検索条件、`GROUP BY` は集計単位、
`ORDER BY` は結果の並び順を指定します。同じ SQL を使っても、サポートされる変更操作と
保存特性はテーブルタイプによって異なります。
### 現在の状態と時系列履歴
「設備 A の現在の温度は何度か」と「過去1時間に温度がどう変化したか」は異なる問いです。
現在値だけを上書きし続けると、過去の変化は分かりません。各計測値に時刻を付けて新しい行として
保存すれば、推移、最大値、異常の発生時刻を分析できます。
時系列システムでは、この履歴が増え続けます。入力速度だけでなく、どの対象のどの時間範囲を
検索するか、元データをどれだけ保持するかも設計する必要があります。計測値が必ず一定間隔で
到着するとは限りません。ネットワーク遅延、設備停止、再送信によって遅延到着や欠測が生じます。
### 計測値、イベント、参照データ
計測値は、ある対象がある時刻にどのような値を持っていたかを表します。イベントは、アラーム、
設備停止、サービス開始など、何かが発生した事実を記録します。設備名、設置場所、計測単位は、
その記録を解釈するための参照データです。
これらは1つのシステムで併用します。温度異常の分析には、温度履歴だけでなく、同じ時刻の
アラームとセンサーの設置場所も必要です。SQL の結合(`JOIN`)は、設備コードなどの共通値を
使って履歴と参照データを関連付けます。
## Machbase で解決する課題
Machbase の時系列機能は、次の処理を組み合わせる場合に利用できます。
| 作業 | 例 | 関連機能 |
|---|---|---|
| 元の履歴を収集 | センサー計測値と設備イベントを継続的に保存 | TAG・LOG、SQL 入力、SDK Append |
| 必要な範囲を検索 | 設備 A の直近1時間の温度変化を確認 | タグ・時間条件、インデックス、実行計画 |
| 統計を繰り返し取得 | 長期間の分・時間単位の推移を比較 | TAG ROLLUP |
| データを解釈 | センサーコードに設備名と場所を関連付け | 参照データ、JOIN |
| 保持期間を管理 | 保持期間を過ぎた元データを削除 | 対応テーブルの Retention Policy |
| 障害に備えて保護 | バックアップと復旧手順を検証 | Edition 別のバックアップ・復旧機能 |
ROLLUP は元データから区間統計を計算します。圧縮は保存に必要な領域を削減する技術、
Retention Policy は古いデータを削除するポリシーです。それぞれ目的が異なり、集計があるだけで
元データを削除してよいわけではありません。
必要な性能は、データ型、入力量、同時クエリ、保持期間、サーバーリソースによって変わります。
小さな演習で操作を学んだ後、実データと実際の検索条件でスループットと遅延を測定してください。
各機能の役割は[基本概念](/ja/dbms/core-concepts/)で詳しく説明します。
## データに適したテーブルの選択
| テーブル | 主な用途 | 選択時の確認事項 |
|---|---|---|
| TAG | タグ名と時間・距離軸を持つ計測履歴 | 特定タグの範囲検索と集計が中心か確認します。 |
| LOG | 複数項目を持つイベント・ログ履歴 | 新しい記録を追記し、時間条件や検索条件で読み出すか確認します。 |
| LOOKUP | 設備コードやマッピングなどの永続的な参照データ | メモリに読み込むデータのサイズと変更方式を確認します。 |
| TRANSACTION | 行単位の変更とトランザクションを必要とする業務データ | Standard Edition で関係型 DML とトランザクションが必要か確認します。 |
| VOLATILE | 再起動後に再生成できる共有状態 | サーバー停止でデータが消えても復元できるか確認します。 |
Machbase DBMS 8.7.0 では、LOG テーブルを `CREATE LOG TABLE` と明示して作成します。
タイプを省略した `CREATE TABLE` は TRANSACTION テーブルを作成します。TRANSACTION は
Standard Edition でサポートされます。
業種だけでテーブルを決めることはできません。変更、結合、保持の要件を含む最終的な選択は、
[テーブルタイプの選択](/ja/dbms/data-modeling-table-design/table-types-selection-type/)で確認してください。
続いて、[10分クイックスタート](../quick-start/)でイベントを1件保存し、読み出してみましょう。
---
title: "1.2 10分クイックスタート"
url: https://docs.machbase.com/ja/dbms/getting-started/quick-start/
language: ja
kind: page
---
# 1.2 10分クイックスタート
稼働中のサーバーに接続し、サービス開始イベントを1件保存して読み出します。
追記型のイベントに適した LOG テーブルを使用し、SQL の実行結果と2つの時刻列の意味を確認します。
インストール時間は、この演習の所要時間に含みません。
## 前提条件
- Machbase DBMS サーバーが `127.0.0.1:5656` で稼働していること。
- `machsql` コマンドを使用できること。
- テーブルの作成・入力・検索・削除権限を持つ演習用アカウントで接続できること。
- 以下は初期演習用アカウント `SYS` とパスワード `MANAGER` を使用します。
変更済みの場合は実際のパスワードに置き換えてください。
- `/tmp` に SQL ファイルを保存でき、演習用の名前 `DBMS_GS_QUICK` を使用できること。
既存の業務テーブルと名前が重ならない演習環境を使用します。最後の `DROP TABLE` は、
演習用テーブルと入力したデータを削除します。
サーバーが未準備の場合は、[インストール・デプロイ・アップグレード](/ja/dbms/installation-deployment-upgrade/)と
[Linux Standard Edition のインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux)を
先に参照してください。
## 実行例
サービス開始イベントを1件 LOG テーブルに記録します。`CREATE LOG TABLE` でタイプを明示して作成すると、
`_arrival_time` 列が自動的に追加されます。
次のコマンドで SQL ファイルを保存し、実行します。
```bash
cat > /tmp/dbms_gs_quick.sql <<'SQL'
CREATE LOG TABLE DBMS_GS_QUICK (
EVENT_ID INTEGER,
EVENT_TIME DATETIME,
LEVEL VARCHAR(10),
MESSAGE VARCHAR(40)
);
INSERT INTO DBMS_GS_QUICK (EVENT_ID, EVENT_TIME, LEVEL, MESSAGE)
VALUES (
1,
TO_DATE('2026-07-02 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),
'INFO',
'service started'
);
SELECT _arrival_time, EVENT_ID, EVENT_TIME, LEVEL, MESSAGE
FROM DBMS_GS_QUICK
ORDER BY EVENT_ID;
DROP TABLE DBMS_GS_QUICK;
SQL
machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER -f /tmp/dbms_gs_quick.sql
```
### 結果の確認
各 SQL ステップでエラーがないことを確認します。SELECT 結果は1行で、`EVENT_ID` が `1`、
`LEVEL` が `INFO`、`MESSAGE` が `service started` である必要があります。
`EVENT_TIME` はアプリケーションが保存したイベントの実際の発生時刻、`_arrival_time` は
この例で DBMS が自動記録したサーバー受信時刻です。実行のたびに `_arrival_time` は変わり、
`EVENT_TIME` と一致する必要はありません。
`CREATE LOG TABLE` は構造を作成し、`INSERT` は1行を追加します。`SELECT` は読み出す列、
`ORDER BY EVENT_ID` は結果の順序を指定します。最後の `DROP TABLE` まで成功すると、
演習用テーブルは削除されます。データをさらに調べる場合は、実行前に最後の DROP 文を除き、
検索が終わってからその演習用テーブルだけを削除します。
再実行時に `DBMS_GS_QUICK` がすでに存在するエラーが出る場合、前の実行が `DROP TABLE`
まで進まなかった可能性があります。`DESC DBMS_GS_QUICK;` で構造を確認し、前の演習で作成した
テーブルである場合に限り `DROP TABLE DBMS_GS_QUICK;` を実行して再試行します。
接続エラーの場合は、まずサーバーアドレス、ポート、起動状態、アカウント情報を確認します。
## この例で確認したこと
| 項目 | 確認内容 |
| --- | --- |
| サーバー接続 | `machsql` で `127.0.0.1:5656` に接続 |
| テーブル作成 | `CREATE LOG TABLE` で LOG テーブルを明示的に作成 |
| データ入力 | `INSERT` と `TO_DATE` でイベントを保存 |
| データ取得 | `SELECT` と `ORDER BY` で入力結果を確認 |
| 自動列 | LOG テーブルの `_arrival_time` をサーバーが自動記録 |
| 後片付け | `DROP TABLE` で演習用テーブルを削除 |
---
title: "1.3 基本コマンド早見表"
url: https://docs.machbase.com/ja/dbms/getting-started/command-cheatsheet/
language: ja
kind: page
---
# 1.3 基本コマンド早見表
接続コマンドは OS のターミナルで、SQL は接続済みの `machsql` で実行します。
サーバーアドレス、ポート、アカウントは実環境に合わせてください。以下の `MANAGER` は
クイックスタートの初期演習用パスワードです。変更済みの場合は、そのアカウントの現在のパスワードを使います。
## ターミナルで実行するコマンド
| 作業 | コマンド |
|---|---|
| 対話接続 | `machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER` |
| SQL ファイルの実行 | `machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER -f file.sql` |
## machsql で実行する SQL
| 作業 | コマンド |
|---|---|
| テーブル一覧 | `SHOW TABLES;` |
| 列と型の確認 | `DESC table_name;` |
| TRANSACTION テーブルの作成 | `CREATE TRANSACTION TABLE table_name (...);` |
| LOG テーブルの作成 | `CREATE LOG TABLE table_name (...);` |
| データ入力 | `INSERT INTO table_name VALUES (...);` |
| 条件に一致するデータの検索 | `SELECT ... FROM table_name WHERE ...;` |
| 結果の並べ替え | `SELECT ... FROM table_name ORDER BY ...;` |
| テーブルとデータの削除 | `DROP TABLE table_name;` |
`table_name` と `...` は、実際の名前と定義に置き換えるプレースホルダーです。
そのまま実行できる SQL は[クイックスタート](../quick-start/)にあります。
`DROP TABLE` はデータも削除するため、削除対象が演習用テーブルであることを先に確認します。
Machbase DBMS 8.7.0 の `CREATE TABLE` は、タイプを省略すると TRANSACTION テーブルを作成します。
TRANSACTION は Standard Edition でサポートされます。タイプを明示すると例の意図が明確になります。
コマンドの詳細は [machsql リファレンス](../../reference/command-line-tools/machsql/)を参照してください。
---
title: "1.4 次に読む文書の選択"
url: https://docs.machbase.com/ja/dbms/getting-started/choose-next-doc/
language: ja
kind: page
---
# 1.4 次に読む文書の選択
クイックスタートでは、1行を保存して検索しました。実際のシステムでは、データの形式に加えて、
変更方法、時刻の基準、クエリパターン、保持期間も決定します。
## 設計前に確認すること
- 同じ対象の値を時系列に蓄積しますか。それとも現在の状態を上書きしますか。
- 計測・発生時刻とサーバー受信時刻のどちらをクエリの基準にしますか。
- 特定タグの範囲検索、複数列の検索、キー検索、結合のうち、よく実行する処理は何ですか。
- 遅延到着、重複、誤った値をどう処理しますか。
- 元データと集計をそれぞれどれだけ保持しますか。再起動後も残す必要があるデータは何ですか。
- 必要な機能はどの Edition で利用できますか。
## 次に読む文書
| 作業 | 次の文書 |
|---|---|
| 時系列履歴、保存、クエリの原理を理解する | [基本概念](../../core-concepts/) |
| テーブルタイプと変更ポリシーを決める | [テーブルタイプの選択とスキーマ設計](../../data-modeling-table-design/) |
| センサー・計測履歴を保存する | [TAG テーブルの利用](../../tag-table-usage/) |
| イベントとログを収集・検索する | [LOG テーブルの利用](../../log-table-usage/) |
| 長期間のタグ統計を取得する | [TAG テーブルの ROLLUP](../../tag-rollup-usage/) |
| 参照データと業務データを管理する | [LOOKUP](../../lookup-table-usage/)、[TRANSACTION](../../rdb-table-usage/) |
| 再生成できる状態を管理する | [VOLATILE テーブルの利用](../../volatile-table-usage/) |
| アプリケーションから入力・クエリを行う | [開発とアプリケーション連携](../../development-tools-integration/) |
| SQL 構文と型を確認する | [SQL リファレンス](../../reference/sql/) |
| 運用・バックアップ・権限を設定する | [運用・設定・復旧](../../operations-configuration-recovery/)、[アカウントと権限](../../security-access-control/) |
まず代表的なデータとよく使うクエリを決め、小規模に実行します。入力速度、クエリの遅延、
保存領域を測定してから、収集方式、インデックス、集計、保持ポリシーを調整します。
---
title: "2. 基本概念"
url: https://docs.machbase.com/ja/dbms/core-concepts/
language: ja
kind: section
---
# 2. 基本概念
1章で SQL によるデータの保存と読み出しを確認した後、この章では設計と運用の観点から動作を理解します。
同じデータでも、時刻の意味、変更方式、クエリ範囲によって適切なテーブルと保存戦略は変わります。
例えば、設備の現在の温度と先月の温度履歴では、保持する行数が異なります。月平均温度と
瞬間的な異常値の検出では、必要なデータの解像度が異なります。この違いを理解すると、テーブル、
インデックス、ROLLUP、保持ポリシーを目的に合わせて選択できます。
## この章の構成
| 節 | 扱う問い |
|---|---|
| [データモデルの概念](concepts/) | 1行に何を保存し、時刻・NULL・重複・変更をどう解釈するか。 |
| [ストレージと実行の構造](storage-execution-architecture/) | 必要なデータをどう見つけ、ストレージ・インデックス・キャッシュがどのコストを削減するか。 |
| [主要機能と用語の区別](features-concepts/) | 元データ・集計・保持・バックアップはそれぞれ何を担うか。 |
| [Edition の概念](concepts-edition/) | 単一サーバーと分散構成をどう選び、どの機能差を確認するか。 |
例では概念説明用の小さなデータセットを使います。機能別の SQL、サポート範囲、運用手順は、
本文からリンクした詳細文書を参照してください。概念を理解したら、
[テーブルタイプの選択とスキーマ設計](../data-modeling-table-design/)で実データに適用します。
---
title: "2.1 データモデルの概念"
url: https://docs.machbase.com/ja/dbms/core-concepts/concepts/
language: ja
kind: page
---
# 2.1 データモデルの概念
データモデルは、1件として何を保存し、どの値で識別し、どう変更・検索するかを定める規則です。
時系列モデルでは、計測対象、時刻、値の意味を併せて定義します。列名を決める前にこの規則を
確認すると、入力と分析結果を一貫して解釈できます。
## 時系列データを理解する
時系列データは、時間に沿った観測やイベントの記録です。温度計測、約定履歴、サービスエラーログなどが
代表例です。一定間隔でもイベント発生時だけでも収集できます。保存順序と発生順序が同じとは限りません。
### 1行の意味と識別子
温度履歴の1行を「1つのセンサーが特定時刻に測定した値」と定義した場合、センサー識別子、計測時刻、
値が必要です。識別子はデータの対象を区別し、時刻は対象の変化を解釈する基準になります。
複数センサーが同じ時刻に測定できるため、時刻だけでは行を一意に識別できません。同じセンサーの
同じ時刻のデータも再送されることがあります。重複を許すか、排除するか、別のイベント番号を設けるかを
決めてください。TAG の `PRIMARY KEY` はタグを識別し、関係型テーブルの行キーのように
各計測行の名前を一意にするものではありません。重複処理は
[TAG テーブルの運用](../../tag-table-usage/operations-lifecycle/)で確認します。
### 値、単位、品質
数値だけでは単位や意味が分かりません。同じ `23.5` でも温度、圧力、電圧は異なります。
タグ定義や参照データで単位と計測場所を管理し、1つの時系列で値の意味を一貫させます。
`NULL` と `0` も区別します。機器が0を計測したことと、計測に失敗して値が不明なことは異なります。
必要なら品質や状態を別の列に記録します。未収集の区間には行自体がないこともあり、
NULL の行が存在する場合とも区別する必要があります。
一般的な `AVG` などの集計は NULL 以外の値に適用されます。欠測をすべて0に置き換えたり、
異なる単位を一緒に集計したりすると結果が変わります。対応集計関数の正確な NULL 処理は
[関数リファレンス](../../reference/sql/functions/functions-full/)を参照してください。
### 時系列ワークロードの特徴
多くの時系列システムは、新しい行を継続的に入力し、特定対象の時間範囲を検索します。
最新値の監視と長期間の統計分析を併用することもあります。これらのパターンが、追記型の入力、
範囲検索、ROLLUP を使う理由です。
ただし、過去データが常に不変とは限りません。機器時計の誤り、センサー補正、重複収集で修正が
必要になることがあります。最新より古いデータを頻繁に読む業務もあります。実際の入力・検索・
修正パターンを測定して設計してください。
### テーブルタイプの役割
| テーブルタイプ | 概念上の役割 |
|---|---|
| TAG | 名前と時間・距離軸を持つ計測履歴 |
| LOG | 新しい記録を追記し続けるイベントとログ |
| TRANSACTION | トランザクションと行単位の変更を必要とする業務データ |
| LOOKUP | メモリに読み込んで参照する永続的な参照データ |
| VOLATILE | 再起動後に再生成できる共有インメモリ状態 |
履歴と参照データを分けると、全計測行に設備名や場所を繰り返し保存する必要が減ります。
ただし、最新の参照データを過去履歴に結合すると、結果にも現在の名前や場所が表示されます。
発生時点の情報が必要なら、イベントとともに保存するか、参照データの変更履歴を別途設計します。
### 関係型業務モデルと時系列モデル
関係型モデルと時系列モデルは相互に排他的ではありません。関係型 DBMS でも時系列を保存し、
インデックス・パーティション・集計を利用できます。Machbase もテーブル、SQL、結合、関係型データの
変更機能を提供します。製品名ではなく主なワークロードを基準に比較してください。
| 観点 | 関係型業務データの例 | 時系列履歴の例 |
|---|---|---|
| 行の意味 | 1件の注文の現在の状態 | 1件のセンサー計測またはイベント |
| 変更パターン | キーで見つけた行の更新・削除 | 新規レコードの追加と必要範囲の修正・削除 |
| クエリパターン | キー検索、条件検索、業務テーブルの結合 | 対象・時間範囲の検索、推移、区間統計 |
| 整合性要件 | 複数変更をまとめて確定または取り消す | 欠測・重複・遅延入力と参照可能時点を管理 |
| 保持設計 | 業務ライフサイクルと変更履歴 | 元データの解像度、集計周期、保持期間 |
LOG・TAG の保存・入力特性を TRANSACTION・LOOKUP・VOLATILE にそのまま適用しないでください。
最終的な選択は[テーブルタイプの選択](../../data-modeling-table-design/table-types-selection-type/)と
[データ変更ポリシー](../../data-modeling-table-design/alter-data-mutation-policy/)で確認します。
## 書き込み中心のワークロードと append-only モデル
append は既存値を上書きせず、新しい行を追加する方式です。例えば設備状態が `RUNNING` から
`STOPPED` に変わった際にイベントを追加すると、以前の状態と遷移時刻を保持できます。
現在状態を直接参照するテーブルと、変更履歴を保存するテーブルを分けて運用することもできます。
### テーブルタイプと変更モデル
LOG は追記型の履歴テーブルで、一般的な行 `UPDATE` をサポートしません。TAG は計測履歴を追加し、
対応する条件と Edition の範囲で DATA 値を補正できます。タグ名や時間軸まで任意に変更する
一般的な行更新とは異なります。
TRANSACTION は関係型 DML と明示的トランザクションを提供し、LOOKUP・VOLATILE は参照データや
状態の変更に使います。すべてのテーブルタイプが同じ変更機能を持つと考えず、
[データ変更ポリシー](../../data-modeling-table-design/alter-data-mutation-policy/)を確認してください。
追記型設計は、継続入力と過去行の任意更新を併用する場合の競合を減らせます。ただし DBMS 内部の
同期や障害復旧処理がすべてなくなるわけではありません。保存構造だけでロック不要や特定の
スループットを保証することはできません。
### SQL 入力と SDK Append
SQL `INSERT` は SQL 文で値を入力し、実行結果を確認する経路です。SDK Append は継続収集のために
複数行を転送する入力 API です。バッファリング、転送、エラー確認、終了処理は各 SDK の仕様に従います。
アプリケーションのバッファへ入れた時点、サーバーが処理した時点、障害後も復旧できる時点は異なります。
LOG・TAG の Append は TRANSACTION テーブルの明示的トランザクションで `ROLLBACK` する対象ではありません。
TRANSACTION への Append のトランザクション参加とエラー処理は、使用する SDK の仕様を確認します。
入力確認と再試行は[データの入力とエクスポート](../../development-tools-integration/data-input-load-export/)
を参照してください。
### 修正、スキーマ変更、保持
誤った LOG イベントは、修正イベントを追記して履歴を残せます。削除して再入力する場合は、
LOG で許される時間ベースの削除範囲と入力順序を先に確認します。特定の1行だけを任意に削除できるとは
限りません。TAG の値補正は [TAG データ補正の設計](../../tag-table-usage/tag-data-update-correction/#design-correction-tag)
に従います。
列の追加・削除と型変更も別の機能です。LOG・TAG のすべてのスキーマ変更が禁止されているわけではなく、
タイプと DATA・METADATA 領域によってサポート範囲が異なります。
[DDL 構文](../../reference/sql/syntax/ddl-syntax/)を確認してから実施します。
元データの追記を続けると保存領域が増えます。元データの保持期間と ROLLUP 統計の目的は別々に定めてください。
集計を作成しても元データは削除されません。
## 時間モデルと _arrival_time
### 発生時刻と受信時刻
発生時刻は機器が計測した、またはイベントが発生した時刻です。受信時刻は DBMS がレコードを受け取った時刻です。
09:00 の計測値をネットワーク復旧後の09:05に受信すると、差は5分です。計測の推移には発生時刻、
収集遅延の分析には両方の時刻の比較が必要です。
時刻の精度、タイムゾーン、時計の正確さも区別します。ナノ秒を表現できても、センサーの時計が
ナノ秒単位で正確とは限りません。DATETIME 文字列の解釈や表示に使うタイムゾーンは
[タイムゾーン設定](../../reference/configuration/configuration-timezone/)を参照してください。
### LOG テーブルの `_arrival_time`
LOG には `_arrival_time` DATETIME 列が自動追加されます。値を省略する通常の入力ではサーバー受信時刻を
記録します。別途発生時刻が必要なら、一般の DATETIME 列を定義します。
```sql
CREATE LOG TABLE device_events (
device_id VARCHAR(20),
event_time DATETIME,
status VARCHAR(20)
);
```
`_arrival_time` を明示する入力経路もあるため、この列が常に実際の受信時刻を表すとは限りません。
明示入力の時刻順序と制約は [LOG の時間モデル](../../log-table-usage/arrival-time-model/)を確認します。
```sql
SELECT device_id, event_time, status
FROM device_events
WHERE _arrival_time >= TO_DATE('2026-07-03 09:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND _arrival_time < TO_DATE('2026-07-03 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY _arrival_time;
```
開始を含み終了を含まない `[開始, 終了)` の範囲を使うと、連続区間の境界を二重集計する誤りを減らせます。
`BETWEEN` は両端を含むため、目的に合わせて選びます。LOG の `DURATION` は `_arrival_time`
を基準に範囲を限定します。
### TAG テーブルの BASETIME 列
時間軸 TAG テーブルでは、`BASETIME` 属性を持つ DATETIME 列へアプリケーションが時刻を入力します。
LOG の自動 `_arrival_time` 列は使用しません。
```sql
CREATE TAG TABLE sensor_values (
name VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
INSERT INTO sensor_values
VALUES ('temp_sensor_01',
TO_DATE('2026-07-03 08:55:00', 'YYYY-MM-DD HH24:MI:SS'),
23.1);
```
この例の `name` はセンサー、`time` は計測時刻、`value` は計測値です。`SUMMARIZED` は
ROLLUP などの統計機能が使用する代表的な数値列を指定します。テーブルを作成するだけで
必要なすべての周期の集計が作られるわけではありません。
TAG には時間の代わりに数値軸を使う BASE DISTANCE モデルもあります。距離・位置に沿った計測では
このモデルを検討しますが、時間軸専用の関数やポリシーをそのまま適用してはいけません。
[TAG スキーマ](../../tag-table-usage/table-structure-schema/)で軸別の規則を説明します。
### 2つの時間モデルの比較
| 項目 | LOG | 時間軸 TAG |
|---|---|---|
| 特殊な時刻列 | 自動生成される `_arrival_time` | 宣言した `BASETIME` 列 |
| 入力時刻の意味 | 通常はサーバー時刻、明示入力時は指定値 | アプリケーションが指定する時刻 |
| 別の発生時刻 | 一般の DATETIME 列に保存可能 | BASETIME を発生時刻として使用可能 |
| 主な設計課題 | どのイベントとフィールドを検索するか | どのタグのどの範囲を分析するか |
発生時刻が必要なだけで LOG を除外する必要はありません。時刻の意味に加え、タグ構造、検索・集計、
更新・削除条件でテーブルを選んでください。LOOKUP・VOLATILE・TRANSACTION の DATETIME は一般列であり、
LOG・TAG の特殊な時間軸機能は自動付与されません。
行の保存順序と結果の表示順序も区別します。順序が重要なら `ORDER BY` を明示し、
同じ時刻の行まで区別する場合は追加のソートキーを指定します。
---
title: "2.2 ストレージと実行の構造"
url: https://docs.machbase.com/ja/dbms/core-concepts/storage-execution-architecture/
language: ja
kind: page
---
# 2.2 ストレージと実行の構造
クエリ時間は SQL 文の長さだけでは決まりません。読み出すデータ量、条件による範囲の絞り込み、
ソート・結合・集計に必要な処理が重要です。この節では、ストレージ、インデックス、キャッシュが
それぞれどのコストを削減するかを説明します。
## Machbase アーキテクチャの概要
ユーザーは `machsql` または SDK で入力・クエリ要求を送ります。サーバーは SQL 構文、オブジェクト、
権限を確認し、実行方法を決め、保存データにアクセスして結果を返します。保存・実行方式は
テーブルタイプと Edition によって異なります。
### Standard Edition の構造
Standard Edition は単一のデータベースサーバーで SQL 処理とデータ保存を行います。LOG・TAG の
時系列入力に加え、TRANSACTION の関係型データ変更、LOOKUP・VOLATILE の参照データや状態管理も、
各テーブルの特性に合った経路で処理します。
```text
クライアント: machsql または SDK
│ 入力・クエリ要求
▼
Machbase DBMS サーバー
SQL 解析と実行計画
テーブル別ストレージ・インデックスアクセス
メモリバッファとバックグラウンド処理
│
▼
テーブルタイプに応じた保存データ
```
この図は役割を示す概念図です。すべての要求が同じ保存経路を通ることや、API 呼び出し直後に
ディスクへ書き込まれることを意味しません。
### Cluster Edition の構造
Cluster Edition は複数ノードで役割を分担します。通常のアプリケーション SQL 接続は Broker を経由し、
Warehouse が時系列データを保存してクエリを実行します。Coordinator はクラスターメタデータと
ノード状態、Lookup は参照データ処理、Deployer はデプロイとノード管理を担当します。
複数グループへの分散はスループットと容量を分担するため、同一グループ内の複製は障害に備えるためです。
ノードを追加しても、すべてのクエリが同じ比率で高速化したり、すべての障害を自動回復できたりするわけではありません。
構成別の機能差は [Edition の概念](../concepts-edition/)、実際のデプロイと障害対応は
[Cluster のインストール](../../installation-deployment-upgrade/cluster-edition/)と
[Cluster の運用](../../operations-configuration-recovery/cluster/)で確認します。
### 入力とクエリの流れ
入力は、対象テーブル・列の確認、値の変換と検証、データの転送・保存という段階で考えられます。
SQL と Append API は処理結果の確認方法が異なるため、アプリケーションは選択した経路の
エラー処理と完了条件に従います。
クエリは、SQL 解析と実行計画の作成、対象データへのアクセス、条件評価と集計・結合・ソート、
結果の返却という処理で構成されます。常に同じ順序でデータを処理するわけではなく、
実際の実行計画によってアクセス順序は変わります。
## 列指向ストレージと圧縮
### 行指向と列指向
行指向ストレージは同じ行の値をまとめて扱い、列指向ストレージは同じ列の値をまとめて扱います。
次の図は両者の概念を比較する例で、実際のファイル配置そのものではありません。
```text
論理的な行:
(時刻1, センサーA, 23.1)
(時刻2, センサーA, 23.5)
(時刻3, センサーB, 18.0)
行指向: [時刻1, センサーA, 23.1] [時刻2, センサーA, 23.5] ...
列指向: [時刻1, 時刻2, 時刻3] [センサーA, センサーA, センサーB] [23.1, 23.5, 18.0]
```
Machbase の LOG・TAG 時系列ストレージは、列単位のアクセスと圧縮を利用します。多数の行から
一部の列だけを読む分析では、読み出すデータ量を削減できます。ただし温度平均のクエリでも、
センサー・時刻条件があれば、その評価に必要なデータも読みます。
行指向システムもインデックスやパーティションで必要な範囲だけを読めます。行指向は常に全行を読み、
列指向は常に速いと決めつけず、読む行数・列数とアクセス経路を確認してください。TRANSACTION の
関係型ストレージや LOOKUP・VOLATILE のメモリ特性も、LOG・TAG と同じ構造として解釈してはいけません。
### 圧縮が効果的な条件
同じ列には同じ型の値が集まり、センサー値や時刻には繰り返しや類似パターンが現れることがあります。
これらは圧縮に有利です。一方、ノイズの大きな値、不規則な文字列、入力順序が混在するデータでは
結果が異なる場合があります。
時系列の時刻は必ずしも単調増加しません。遅れて到着する計測値や複数収集元の入力が混在するためです。
特定の圧縮方式や圧縮率を前提にせず、型、値の分布、入力順序、設定に応じて実際の圧縮率と性能を測定します。
### パーティションと読み出し範囲
パーティションはデータを管理可能な部分に分割する単位です。検索条件と保存された範囲情報を使って
無関係な部分を読み飛ばすと、読み出しを削減できます。これをパーティションプルーニング
(partition pruning)と呼びます。
LOG・TAG の保存単位は、ユーザーが指定する1日・1か月と一致するとは限りません。タグ・軸の条件、
データ分布、テーブル別の保存構造で実際のアクセス範囲は変わります。時間条件があるだけで
必要なデータしか読まないと判断せず、実行計画と測定結果を確認します。
## インデックスの基本原理
インデックスは条件に一致するデータを見つけるアクセス経路です。対象が全体の一部なら有効ですが、
大半の行を読む集計では別の経路が有利な場合があります。インデックスには保存領域と、
入力・変更時の維持コストも必要です。
| テーブルタイプ | アクセス経路を考える基準 |
|---|---|
| TAG | タグ名と時間・距離軸の範囲 |
| LOG | `_arrival_time` 条件と対応する検索インデックス |
| TRANSACTION | PRIMARY KEY、UNIQUE、一般インデックス |
| LOOKUP・VOLATILE | メモリ上のキーと対応するセカンダリインデックス |
「全センサーの1か月平均」と「センサー A の直近1分の値」では、読むデータの比率が異なります。
同じテーブルでも同じ性能は期待できません。結合では各入力の行数と結合条件も重要です。
対応インデックスと制約は[スキーマオブジェクトの定義](../../data-modeling-table-design/schema-objects-definition/)、
測定と調整は[インデックスのチューニング](../../performance-tuning/index-tuning/)で確認します。
## キャッシュと実行計画
### SQL の実行過程
サーバーは SQL 構文、型、オブジェクトを確認し、条件とインデックスなどから実行可能なアクセス経路を
決めてデータを処理します。実行計画はその処理方法を表します。計画を作るコストと、
計画に従ってデータを読むコストは異なります。
### 実行計画の再利用と PVO Cache
PVO Statement Cache は、再利用できる SQL の解析・検証・最適化結果と実行計画を再利用し、
準備処理の繰り返しを削減します。結果の行を保存するキャッシュではないため、計画を再利用しても
データの読み出しと条件評価は必要です。
Min-Max Cache のように保存データの範囲情報を使うキャッシュは、読み出し対象を減らすためのものです。
実行計画キャッシュとデータアクセス用キャッシュを混同しないでください。どのキャッシュを増やすかは、
ヒット率とメモリ使用量を確認して判断します。
### EXPLAIN による実行計画の確認
次の例は、[データモデルの概念](../concepts/#time-model-arrival-time)で作成した
`sensor_values` テーブルを使用します。
```sql
EXPLAIN SELECT AVG(value)
FROM sensor_values
WHERE name = 'temp_sensor_01'
AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD')
AND time < TO_DATE('2026-07-03', 'YYYY-MM-DD');
```
実行計画でデータアクセスと条件適用を確認します。計画があるだけでは実際の応答時間やディスク読み出し量は
分からないため、代表データで実行時間も測定します。キャッシュが空の初回実行と再利用時の条件を
区別すると、結果を解釈しやすくなります。
PVO Cache のヒット・削除統計は `V$PVO_CACHE_STAT`、キャッシュ済み SQL は `V$PVO_CACHE_LIST` で
確認します。設定と診断は[キャッシュとメモリのチューニング](/ja/dbms/performance-tuning/cache-tuning-memory/#pvo-cache)
を参照してください。
---
title: "2.3 主要機能と用語の区別"
url: https://docs.machbase.com/ja/dbms/core-concepts/features-concepts/
language: ja
kind: page
---
# 2.3 主要機能と用語の区別
Machbase DBMS の長期データ運用に必要な ROLLUP、Retention Policy、Backup・Restore・Mount の
役割と選択基準を説明します。作成構文と運用手順は各機能の詳細文書で扱います。
元データは個々のイベントや計測値の再分析に、集計は多数の元データを要約した繰り返しクエリに使います。
保持ポリシーは何をいつ削除するかを決め、バックアップは障害後の復旧に必要なデータを用意します。
これらを区別すると、集計があるから必要な元データを削除する、複製があるからバックアップを省く、
といった誤りを避けられます。
- **[ROLLUP 統計の役割](#role-statistics-rollup)** — 繰り返し集計のクエリコストを削減する方法
- **[Retention Policy の役割](#role-retention-policy)** — 期間に応じてデータを自動削除する方法
- **[Backup・Restore・Mount の関係](#concepts-backup-restore-mount)** — 保護、復旧、参照の目的の区別
## ROLLUP 統計の役割
TAG の長期間のデータを毎回元の行から集計すると、クエリ範囲が広がるほど処理コストも増えます。
ROLLUP は、時間軸 TAG の指定した数値列などを区間ごとに集計し、繰り返しクエリに使う機能です。
集計対象の列と集計方式は ROLLUP の定義で決まります。
基本 ROLLUP は秒(SEC)、分(MIN)、時間(HOUR)の階層を構成します。テーブル作成時に
`WITH ROLLUP` を指定するか、通常の `CREATE ROLLUP` で必要な周期と条件を指定できます。
生成されるオブジェクト名や内部保存構造に依存せず、公開された ROLLUP SQL で管理してください。
### 選択基準
| クエリパターン | 選択 |
| --- | --- |
| 長期間の分・時間単位の統計を繰り返し取得 | 基本 ROLLUP を検討 |
| 集計周期やフィルター条件を指定 | 周期・条件を指定する通常の ROLLUP を検討 |
| 独自の集計 SELECT の結果を別の TAG に保存 | Standard Edition の Custom ROLLUP を検討 |
| 最初・最後の値が必要 | 拡張 ROLLUP を検討 |
| 元の値のクエリが中心、または集計頻度が低い | ROLLUP なしで開始して実行時間を測定 |
ROLLUP は元データの代わりとなる保持ポリシーではありません。元データの保持期間は Retention Policy で
別途設計し、TAG データを変更した場合は、その範囲の ROLLUP 再構築が必要かも確認します。
### 集計結果の解釈
集計すると情報の解像度が下がります。1分平均だけでは、その1分間の瞬間的な異常値や個々の計測順序を
復元できません。最大・最小値を併せて保持すれば範囲は分かりますが、元の情報がすべて残るわけではありません。
複数区間の平均をさらに平均すると、全体平均と異なる場合があります。2件の平均が10、8件の平均が20なら、
全体平均は `(2 × 10 + 8 × 20) / 10 = 18` であり、2つの平均の単純平均15ではありません。
再集計には合計と有効件数などの必要な統計を使い、ROLLUP の対応クエリ関数に従います。
ROLLUP 処理は元データの入力と別に進むため、最新の元データと集計が反映される時点は異なることがあります。
遅延到着や値の補正がある場合は、元データの範囲、集計の進行状態、再構築の必要性を併せて確認します。
作成構文、クエリ関数、再構築手順は [TAG・ROLLUP の利用](/ja/dbms/tag-rollup-usage/)を参照してください。
## Retention Policy の役割
Retention Policy は、LOG または TAG で保持期間を過ぎたデータを所定の周期で削除します。
データが流入し続けるテーブルの保存領域を、管理者が手動削除を繰り返さずに管理するために使います。
| 要件 | 選択 |
| --- | --- |
| 一定期間を過ぎたデータを継続的に自動削除 | Retention Policy |
| 誤入力した範囲を直ちに削除 | テーブルタイプが対応する `DELETE` |
| 対応テーブルの全データを削除 | `TRUNCATE TABLE` |
Retention を適用しても、すべての古いデータが直ちに消えるわけではありません。実行周期、
対象テーブルのサポート範囲、実際の削除状態を確認します。LOOKUP、VOLATILE、TRANSACTION の
データライフサイクルは、各テーブルが対応する明示的な DML で管理します。
保持期間は入力量とともに必要な保存容量を決めます。毎秒の入力件数に保持秒数を掛けると元の行数を
概算できますが、実際のディスク容量は型、圧縮、インデックス、複製、バックアップにも左右されます。
元データを削除する前に、集計の範囲・保持期間と、監査・再分析に必要な解像度を確認します。
ROLLUP を作成しても、元データの保持期間は自動的には変わりません。
ポリシーの作成・適用・解除構文と運用点検は、
[データ保持ポリシー](/ja/dbms/operations-configuration-recovery/policy-data-retention/)を参照してください。
## Backup・Restore・Mount の関係
3つともバックアップデータに関わる機能ですが、結果は異なります。
| 機能 | 目的 | 運用サーバー | 結果 |
| --- | --- | --- | --- |
| Backup | 復旧用コピーの作成 | 稼働中に実行可能 | 別のパスにバックアップを作成 |
| インスタンス Restore | バックアップからインスタンスを復旧 | オフライン手順が必要 | 運用データベースを復旧 |
| Mount | バックアップ内容を読み取り専用で確認 | 稼働中に実行可能 | 別名でバックアップを検索 |
インスタンスの復旧とは別に、論理データベースを復旧する `RESTORE DATABASE` SQL もあります。
稼働中のサーバーで実行するため、オフラインのインスタンス復旧とは対象と手順を区別します。
Backup の成功だけでは復旧手順を検証したことになりません。対応 Edition で Mount による内容確認、
または隔離環境での Restore を実施します。バックアップパスの権限と保持周期も管理してください。
Mount はバックアップを運用データへ戻す処理ではなく、マウントしたデータには書き込めません。
Restore と Mount は Standard Edition の機能なので、Cluster ではその Edition のバックアップ・障害復旧手順を確認します。
運用計画では、許容するデータ損失期間(RPO)とサービス復旧までの許容時間(RTO)を決めます。
前者はバックアップ・複製間隔、後者は復旧するデータ量と実際のリストア時間を検討する基準です。
特定の Edition やバックアップ周期だけで両方の目標が保証されるわけではありません。
誤った削除も複製先に反映されることがあるため、複製とバックアップの目的を区別します。
コマンド、権限、Edition 別サポート、復旧順序は
[バックアップ・リストア・マウント](/ja/dbms/operations-configuration-recovery/backup-restore-mount/)を参照してください。
複数の論理データベースを運用する場合は、
[複数データベースの運用](/ja/dbms/operations-configuration-recovery/multi-database/)も確認します。
## 入力経路の比較
小さな SQL 演習には `INSERT`、アプリケーションの継続収集には対応 SDK の Append、ファイルの
読み込みには `machloader` などを検討します。対応テーブル、入力形式、失敗の確認方法が異なるため、
名前が似ているだけでツールを置き換えることはできません。
SQL、SDK、ファイル入力ツールの選択基準は、
[データの入力とエクスポート](/ja/dbms/development-tools-integration/data-input-load-export/#machloader-vs-csvimport-csvexport-tagmetaimport)
を参照してください。
---
title: "2.4 Edition の概念"
url: https://docs.machbase.com/ja/dbms/core-concepts/concepts-edition/
language: ja
kind: page
---
# 2.4 Edition の概念
Edition はデプロイ構成と機能のサポート範囲を決定します。Standard は単一サーバーから始める構成、
Cluster は複数ノードで保存と処理を分担する構成です。現在のデータサイズだけでなく、必要な SQL 機能、
増加率、障害対応、運用体制を考慮して選びます。
## Standard Edition と Cluster Edition の違い
### Standard Edition
1台の DBMS サーバーで SQL 処理とデータ保存を行います。分散ノード間のデプロイや通信を管理する
必要がなく、開発や単一サーバー運用の開始に適しています。TRANSACTION テーブルや Restore・Mount など、
Standard 専用機能が必要かも確認します。
単一サーバー構成だからといって、データ量が小さい必要はありません。入力量、クエリ負荷、保持期間が
サーバーの CPU・メモリ・ストレージの容量に収まるかを測定して判断します。
### Cluster Edition
Coordinator、Deployer、Broker、Warehouse、Lookup の各ノードが役割を分担します。
| ノードタイプ | 役割 |
|---|---|
| Coordinator | クラスターメタデータとノード状態の管理 |
| Deployer | パッケージの配布とノード管理 |
| Broker | アプリケーションの SQL 接続とクエリ分配 |
| Warehouse | 時系列データの保存とクエリ実行 |
| Lookup | クラスターの参照データ処理 |
通常の SQL アプリケーションは Broker に接続します。管理ツールの接続先とポートは役割別に異なるため、
SQL 接続先と管理接続先を区別します。
複数の Warehouse グループにデータを分散することと、同じグループ内でデータを複製することは目的が異なります。
分散は容量・スループットの拡張、複製は障害対応に使います。ノード数、複製状態、クライアントの再接続、
障害時の運用手順をまとめて設計する必要があります。
### 機能のサポート差
| 確認項目 | Standard Edition | Cluster Edition |
|---|---|---|
| 主なデプロイ構成 | 単一 DBMS サーバー | 役割を分担する複数ノード |
| TRANSACTION テーブル | サポート | 非サポート |
| Restore・Mount | サポート | 非サポート |
| 容量・処理の拡張 | サーバーリソースとストレージ構成の拡張 | 分散グループとノード構成の拡張 |
| 障害対応の設計 | バックアップ・復旧手順、サーバー運用計画 | ノード・グループの複製と状態、接続・復旧手順 |
LOG・TAG・LOOKUP・VOLATILE、ROLLUP、Retention などの共通機能も、DML・DDL・運用の細かい制約が
すべて同じとは限りません。全体のサポート範囲は
[Edition 別サポート](../../reference/support-scope-constraints/edition/)と
[テーブルタイプ別サポート](../../reference/support-scope-constraints/table-types-type/)で確認します。
### 選択基準
1. 必須機能を確認します。TRANSACTION や Restore・Mount が必要なら、まず Standard のサポート範囲を確認します。
2. 代表的な入力とクエリを実行します。データ型、同時接続数、クエリ範囲、保持期間を実業務に近づけ、
単一サーバーの余力を確認します。
3. データ増加率と障害要件を考慮します。単一サーバーを超える分散が必要なら、Cluster のネットワーク、
複製、ノード運用コストも評価します。
4. 障害シナリオを試験します。ノード監視があることと無停止で復旧できることは別です。
復旧時間とアプリケーションの再接続・再試行動作を確認します。
運用中の Edition 変更も、サーバー数を増やすだけの作業ではありません。使用中の SQL・SDK と、
データ移行・バックアップ・復旧方法の互換性を先に確認します。
## 関連文書
- [ストレージと実行の構造](../storage-execution-architecture/)で処理の流れを説明します。
- [インストール・デプロイ・アップグレード](../../installation-deployment-upgrade/)でデプロイ手順を説明します。
- [バージョンと互換性](../../reference/support-scope-constraints/compatibility-version/)でバージョン別のサポート範囲を確認します。
- [関係型業務モデルと時系列モデル](../concepts/#differences-rdbms)でデータモデルの選択基準を説明します。
---
title: "3. インストール、デプロイ、アップグレード"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/
language: ja
kind: section
---
# 3. インストール、デプロイ、アップグレード
本章ではMachbase DBMS 8.7.0をインストールし、データを入力・検索できる状態か確認します。
新しいサーバーの準備と、既存データを保持するアップグレードでは出発点が異なります。
まず必要な機能とデプロイ環境を決め、状況に合う手順を選択します。
第2章のデータモデルとEditionの違いはインストールにも影響します。TRANSACTIONテーブルやRestore・Mountが
必要ならStandard Editionのサポート範囲を確認します。分散保存とレプリケーションが必要なら、Clusterの
ノードの役割、ネットワーク、障害対応も設計します。
## インストール経路の選択
| Edition | デプロイ構造 | 選択時の確認事項 |
|---|---|---|
| Standard Edition | 1つのDBMSサーバーがSQL処理と保存を実行 | 必要な機能と入力・検索・保管の負荷をサーバーリソースで処理できるか |
| Cluster Edition | Coordinator・Deployer・Lookup・Broker・Warehouseの役割を分離 | 分散グループ、レプリケーション、通信経路、ノード運用手順をまとめて準備できるか |
単一サーバーが小規模データしか扱えないという意味ではありません。必要な保存容量と性能を代表データで
測定して判断します。一方、Clusterもノード数を増やせば全クエリが比例して速くなるわけではありません。
詳しい選択基準は
[Editionの違い](/ja/dbms/core-concepts/concepts-edition/#differences-standard-edition-cluster)を参照してください。
### インストール前に区別する対象
| 対象 | 意味 | 確認例 |
|---|---|---|
| 配布パッケージ | 実行ファイル、ライブラリ、サンプル設定 | バージョン・Edition・OS・CPUアーキテクチャー |
| インストールホーム | 1つのサーバーまたはノードが使用する実行・設定パス | `MACHBASE_HOME`、`conf/machbase.conf` |
| データ保存パス | DBMSが実データを読み書きする場所 | `DBS_PATH`、空き容量、アクセス権 |
| サーバーインスタンス・ノード | その設定で実行されるDBMSプロセス | 起動状態、ログ、接続ポート |
| 論理データベース | 接続後にSQLオブジェクトを作成・使用する空間 | 現在のデータベース、ユーザー・権限・テーブル |
パッケージの展開、新規インスタンスのデータベース作成、サーバー起動、テーブル作成は別々の段階です。
既存データがあるホームに新規インストール用の初期化コマンドを実行しないでください。
インストールホームと実際のデータパスが異なる場合もあるため、バックアップ・アップグレード前に両方を確認します。
SQLの論理データベースはインストールホームとは別の概念です。
複数データベース運用時の選択・作成・権限は
[マルチデータベース運用](/ja/dbms/operations-configuration-recovery/multi-database/)で説明します。
## インストール手順
### Standard Edition
1. [インストール前の準備](./pre-install-preparation/)でパッケージ、サーバーアカウント、リソース、ポートを確認します。
2. OSに合う手順で専用ホームと環境変数を準備します。
- [Linux — Tarballインストール](./standard-edition/#linux-tarball)
- [Linux — Dockerインストール](./standard-edition/#linux-docker)
- [Windows — パッケージインストール](./standard-edition/#windows-package)
3. 設定とデータパスを確認し、別途ライセンスを使用する場合は初回起動前に
[ライセンスのインストール](./pre-install-preparation/#license)を行います。
4. 選択した手順に従い、新しいデータベースを作成してサーバーを起動します。
5. [インストール検証チェックリスト](./validation-checklist/)でプロセス・ポート・接続・バージョン・
ライセンスと、少量データの入力・検索を確認します。
コンテナーでもパッケージのバージョン、データボリューム、実行アカウントの書き込み権限を確認します。
コンテナーの起動とDBMSの初期化・起動の関係はイメージにより異なるため、該当する手順に従います。
### Cluster Edition
1. [インストール前の準備](./pre-install-preparation/)と
[クラスター環境の準備](./cluster-edition/#preparation-environment-cluster-edition)を確認します。
2. ノード別のホスト、ホーム、SQL・管理・ノード間通信のポートとWarehouseレプリケーショングループを決めます。
3. 使用するパッケージとライセンスを準備し、デプロイ方式を選択します。
- [machclusterctlによるデプロイ](./cluster-edition/#machclusterctl): 設定ファイルでデプロイし、実行計画を確認
- [手動インストール](./cluster-edition/#manual-machcoordinatoradmin): 管理ツールで段階的に登録・起動
4. ノードの役割に応じた状態とレプリケーション構成を確認し、BrokerへSQLで接続します。
5. [インストール検証チェックリスト](./validation-checklist/)でデータの入力・検索とグループ内の
レプリケーション状態を区別して確認します。
SQL接続の成功と全レプリカの正常状態は別の確認です。異なるWarehouseグループが必ず同じデータを
持つわけでもありません。障害対応は[Cluster運用](/ja/dbms/operations-configuration-recovery/cluster/)で
続けて確認してください。
## アップグレード
既存システムには[アップグレード](./upgrade/)の手順を使用します。新パッケージの実行可否だけでなく、
データファイル、SQL・SDK、設定・ライセンス、バックアップ・復旧経路の互換性を確認します。
本番設定を新パッケージのサンプルで上書きしたり、実行ファイルを交換しただけで完了と判断したりしないでください。
アップグレード前の基準測定値とバックアップを確保し、隔離環境で復旧に必要な時間も確認します。
旧バージョンへ戻せるかの判断には、バイナリだけでなく旧バージョンで読めるデータと設定が必要です。
## 次のステップ
インストール検証は本番準備の始まりです。まず[クイックスタート](/ja/dbms/getting-started/quick-start/)で
SQLの流れを学び、[テーブルタイプの選択とスキーマ設計](../data-modeling-table-design/)で実データを
モデル化します。本番投入前に専用アカウント、収集エラー処理、保管・バックアップ、代表負荷テスト、
監視メトリクスを準備します。
[観測と診断](/ja/dbms/operations-configuration-recovery/diagnosis-observability/)と
[性能チューニングの進め方](/ja/dbms/performance-tuning/performance-approach/)で、その過程を案内します。
---
title: "3.1 インストール前の準備"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/pre-install-preparation/
language: ja
kind: page
---
# 3.1 インストール前の準備
インストール前の準備では、実行ファイルのコピー先だけでなく、データの保存先、サーバーの実行アカウント、
クライアントの接続経路を確定します。パッケージとOSの互換性を確認してから、ストレージ、ネットワーク、
ライセンスを準備します。サポート範囲は提供されたパッケージのリリース情報と技術サポートポリシーで判断します。
## 先に決めるデプロイ情報
| 項目 | 決定事項 | 必要な理由 |
|---|---|---|
| Editionとバージョン | StandardまたはCluster、サーバー・SDKバージョン | 使用するSQL機能とデプロイ方式の決定 |
| OSアカウント | サーバー実行アカウントとファイル所有者 | 設定・データ・ログのパスのアクセス権を合わせる |
| インストールホーム | 実行ファイルと設定がある絶対パス | 管理コマンドが操作するインスタンスを識別 |
| データパス | 実際の`DBS_PATH`、ファイルシステム、空き容量 | 再起動・アップグレード時に保持するデータを識別 |
| 接続情報 | サーバーアドレス、SQLポート、管理ポート、許可クライアント | ポート競合と誤ったインスタンスへの接続を防止 |
| 復旧とライセンス | バックアップ保存先、復元手順、使用ライセンス | 障害対応と運用範囲の確認 |
OSアカウント`machbase`とDBユーザー`SYS`は異なります。前者はプロセス・ファイルの権限、後者は
SQL接続とデータベース操作の権限を決めます。サーバー起動が成功しても、ファイル権限やSQL権限が
適切でなければロード・バックアップなどが失敗する場合があります。
| 項目 | 説明 |
|------|------|
| [インストール前の要件](/ja/dbms/installation-deployment-upgrade/pre-install-preparation/#pre-install-requirements) | OSバージョン、ハードウェア最小要件、ネットワークポート |
| [パッケージ構成の理解](/ja/dbms/installation-deployment-upgrade/pre-install-preparation/#package) | パッケージファイルの命名規則、ディレクトリ構造、主な実行ファイル |
| [ライセンスのインストール](/ja/dbms/installation-deployment-upgrade/pre-install-preparation/#license) | license.datの配置方法、ライセンス状態の確認方法 |
---
## インストール前の要件
### OSとパッケージ
OSの種類とCPUアーキテクチャーはパッケージの表記と一致する必要があります。対応OSと最小バージョンは
リリースごとに変わる場合があるため、固定的なバージョン表ではなく、パッケージ付属のリリース情報で
確認してください。
### システムリソース
CPU、メモリ、ディスク、ネットワークの必要量は、入力レート、保持期間、インデックス、ROLLUP構成により
異なります。インストール領域だけでなく、予想される生データ、バックアップ、運用上の空き容量を含めて
算定し、実際のワークロードで容量とスループットを検証してください。秒間行数と保持期間から元の行数を
予測し、代表データをロードして行サイズ・圧縮・インデックスの実際の保存コストを測定します。
Clusterではレプリカ領域も含めます。同じディスクの別ディレクトリは、別の障害ドメインや独立した
I/Oデバイスではありません。
### デフォルトポート
| ポート | 用途 |
|------|------|
| **5656** | SQLクライアント接続(Native TCP) |
SQLクライアントポートの変更には、`$MACHBASE_HOME/conf/machbase.conf`の`PORT_NO`を設定します。
`MACHBASE_PORT_NO`環境変数も使用するため、サーバーを起動するシェルやサービスの環境変数も確認します。
変更したポートはクライアントにも明示し、実行中のサーバーに新しい環境変数が遡及適用されるとは考えません。
ファイアウォール環境では上記ポートの受信を許可する必要があります。Cluster EditionではCoordinatorの
link/adminポートと、Broker、Warehouse、Deployerのポートも追加で開く必要があります。
### システムカーネルパラメーター(Linux)
Linuxへのインストールでは、事前に以下を確認します。
#### ファイルディスクリプターの上限
多数のファイルを同時に開くワークロードでは、ファイルディスクリプターの上限が低いとボトルネックになる
場合があります。デフォルトの上限はOSとアカウント設定によって異なるため、サーバー実行アカウントで確認します。
```bash
# 現在値を確認
ulimit -Sn
```
このインストール例は65535を使用します。上限がこれより小さい場合は`/etc/security/limits.conf`を
変更し、新しいログインセッションで適用を確認します。
```
* hard nofile 65535
* soft nofile 65535
```
サーバー実行アカウントで再ログインして値を確認します。サービスマネージャーからサーバーを起動する場合は、
そのサービスのファイルディスクリプター上限も別途確認します。
```bash
ulimit -Sn
# 出力: 65535
```
#### ポートの予約
MachbaseサービスのポートがOSの一時ポートの自動割り当てに使われないよう予約します。
この設定は、別プロセスによる同じポートの明示的な使用までは防止しません。
```bash
current=$(cat /proc/sys/net/ipv4/ip_local_reserved_ports)
ports=5656
sudo sysctl -w net.ipv4.ip_local_reserved_ports="${current:+$current,}$ports"
```
既存の予約ポートがある場合は上書きせず、カンマで区切って統合します。永続化するには
`/etc/sysctl.conf`の`net.ipv4.ip_local_reserved_ports`項目と次の値を統合します。
```
net.ipv4.ip_local_reserved_ports = 5656
```
### 時刻同期
時系列データを処理するため、サーバー時刻は正確である必要があります。NTPまたは`chrony`で
システム時刻を同期してください。Cluster Editionは全ノードの時刻を合わせる必要があります。
```bash
# タイムゾーンを確認
ls -l /etc/localtime
date
```
---
## パッケージ構成の理解
### パッケージファイルの命名規則
パッケージのファイル名はEditionに応じて次の形式です。
```
machbase-EDITION-VERSION-OS-CPU-BIT-MODE.EXT
```
| 項目 | 説明 | 例 |
|------|------|------|
| EDITION | Editionの区分 | `SDK`、`cluster` |
| VERSION | バージョン(Major.Minor.Fix.AUX) | `8.7.0.official` |
| OS | オペレーティングシステム | `LINUX`、`WINDOWS` |
| CPU | CPUアーキテクチャー | `X86` |
| BIT | アーキテクチャーのビット数 | `64` |
| MODE | ビルドモード | `release` |
| EXT | 拡張子 | `tgz`(Linux)、`zip`またはインストーラー実行ファイル(Windows) |
Standard EditionのLinux tarballは`machbase-SDK-...tgz`という名前で生成されます。
例:
- Standard Edition: `machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz`
- Cluster Edition: `machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz`
マイナーバージョンが異なると、DBファイルやプロトコルの互換性が変わる場合があります。
Fixバージョン変更も含む実際のアップグレード経路は、対象リリースの互換性情報と
[アップグレード手順](../upgrade/)で確認します。
### インストールディレクトリの構造
tarballを展開すると、`$MACHBASE_HOME`配下に次の構造が作成されます。
```
$MACHBASE_HOME/
├── bin/ 実行ファイル
├── conf/ 設定ファイル(machbase.confなど)
├── dbs/ データ保存領域
├── doc/ ライセンス文書
├── include/ C/C++ヘッダーファイル
├── install/ Makefile用mkファイル
├── lib/ 共有ライブラリ
├── package/ Cluster Editionの追加パッケージパス
├── sample/ サンプルファイル
├── trc/ サーバーログとトレースファイル
├── tutorials/ チュートリアル
├── utility/ ユーティリティファイル
└── 3rd-party/ Grafanaプラグインなど
```
### 主な実行ファイル
| 実行ファイル | 説明 |
|-----------|------|
| `machbased` | サーバーデーモン |
| `machadmin` | サーバー管理(起動・終了・DB作成) |
| `machsql` | CLIクエリツール |
| `machloader` | 大容量ファイルのロード・抽出ツール |
| `csvimport` | CSVファイルのインポート |
| `csvexport` | CSVファイルのエクスポート |
| `tagmetaimport` | TAGメタデータの一括登録 |
Cluster Editionパッケージには`machcoordinatoradmin`、`machdeployeradmin`などの管理ツールが追加されます。
`machclusterctl`は、そのツールを含めてビルドされたパッケージで使用できます。
### 設定ファイル
`$MACHBASE_HOME/conf/`配下にはEdition別のサンプル設定があります。
```bash
ls $MACHBASE_HOME/conf/
# machbase.conf
# machbase.conf.sample.standard
# machbase.conf.sample.edge
# machloader.conf.sample
```
実際に使用するファイルは`machbase.conf`です。Standard fullパッケージはビルド時に
`machbase.conf.sample.standard`をコピーし、`machbase.conf`を含めます。実ファイルがないパッケージでは、
Editionに合うサンプルをコピーして変更します。
Standard/Edgeのサンプルには、TRANSACTIONの書き込み競合と耐久性ポリシーを制御する
`TRANSACTION_BUSY_TIMEOUT_MS`、`TRANSACTION_SYNCHRONOUS`、`TRANSACTION_JOURNAL_MODE`が含まれます。
TRANSACTIONテーブルを使用する場合はまずデフォルト値を使用し、同時書き込みと耐久性の要件を検討してから
調整します。
---
## ライセンスのインストール
ライセンスファイルがない場合、サーバーはデフォルトの`COMMUNITY`ライセンス情報を使用します。
インストール前に、この範囲が予定する機能・容量に合うか確認します。別のライセンスが必要な環境では、
初回サーバー起動前にファイルを準備します。起動できるだけで本番に必要なライセンス条件を満たしたと
判断しないでください。
### ライセンス状態の確認
インストールしたライセンスの状態と制限違反の有無は、`V$LICENSE_INFO`の`VIOLATE_STATUS`と
`VIOLATE_MSG`で確認します。ライセンスファイルの本文は変更しないでください。
### インストール方法
#### 方法1: ファイルのコピー(サーバー起動前)
`license.dat`を`$MACHBASE_HOME/conf/`にコピーします。サーバー起動時に自動認識されます。
```bash
cp license.dat $MACHBASE_HOME/conf/license.dat
```
#### 方法2: machadminコマンド
`machadmin`でライセンスファイルを検証してインストールします。サーバーが実行中の場合は、
ライセンス再読み込み要求も送信します。
```bash
machadmin -t /path/to/license.dat
```
#### 方法3: SQLクエリ(サーバー実行中)
サーバーが実行中の場合は、machsqlのクエリでインストールします。
```sql
ALTER SYSTEM INSTALL LICENSE = '/path/to/license.dat';
```
### インストールの確認
#### machadminで確認
```bash
machadmin -f
```
#### V$LICENSE_INFOビューの検索
```sql
SELECT ID, ISSUE_DATE, TYPE, CUSTOMER, VIOLATE_STATUS, VIOLATE_MSG
FROM V$LICENSE_INFO;
```
`VIOLATE_STATUS`が0なら正常です。
machsqlでは次のコマンドでもライセンス情報を確認できます。
```sql
SHOW LICENSE;
```
---
title: "3.2 Standard Editionのインストール"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/standard-edition/
language: ja
kind: page
---
# 3.2 Standard Editionのインストール
Standard Editionは1台のサーバーでSQL処理とデータ保存を実行します。インストールは、パッケージの準備、
サーバー実行環境の設定、データベース作成、ライセンス確認、起動、SQL検証の順に進めます。
単一サーバーでも少量データだけを扱うわけではなく、スループットと保持期間に必要なリソースを
実際のワークロードで確認する必要があります。
## インストール経路
OSに応じて次の経路から選択します。
| OS | インストール方式 | リンク |
|----|-----------|------|
| Linux | Tarball (.tgz) | [Tarballインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux-tarball) |
| Linux | Dockerコンテナー | [Dockerインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux-docker) |
| Windows | ZIPまたはインストーラー実行ファイル | [Windowsパッケージインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#windows-package) |
事前に[Linux環境の準備](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux-preparation-environment-linux)または
[Windows環境の準備](/ja/dbms/installation-deployment-upgrade/standard-edition/#windows-preparation-environment-windows)を確認してください。
---
## Linuxへのインストール
LinuxでStandard Editionをインストールする方法は2つあります。
| 方式 | 適している状況 |
|------|------------|
| [Tarballインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux-tarball) | 実サーバー環境、データディレクトリを直接管理する場合 |
| [Dockerインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#linux-docker) | 開発・テスト環境、すぐに起動する必要がある場合 |
Tarballのインストールは[インストール前の準備](../pre-install-preparation/)を先に完了します。
DockerではDocker Engineとボリューム・ポートの権限を準備してください。
---
### Linux環境の準備
ファイルディスクリプター上限、時刻同期、ポート予約、ファイアウォール設定はEdition共通です。
[インストール前の準備](../pre-install-preparation/)でサーバー実行アカウントと運用環境に合わせて
設定してから、次の手順に進みます。
---
### Tarballインストール
Linux環境にtarball(.tgz)を展開してStandard Editionをインストールする手順です。
#### 1. ユーザーの作成
Machbase専用のOSユーザーを作成します。
```bash
sudo useradd -m -d /home/machbase machbase
sudo passwd machbase
```
以降は`machbase`アカウントでログインして作業します。
#### 2. パッケージのダウンロードと展開
例ではパッケージを`/home/machbase/packages/`にダウンロード済みとします。以下のパッケージ名を
実際の配布物に置き換え、インスタンスがまだない新しいインストールディレクトリに展開します。
既存インストールの更新は[アップグレード](../upgrade/)手順を使用します。
```bash
machbase_package=/home/machbase/packages/machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz
test -r "$machbase_package" &&
mkdir /home/machbase/machbase_home &&
tar zxf "$machbase_package" -C /home/machbase/machbase_home &&
cd /home/machbase/machbase_home
```
展開後にディレクトリ構造を確認します。
```bash
ls -l
# bin/ conf/ dbs/ doc/ include/ lib/ trc/ ...
```
#### 3. 環境変数の設定
`~/.bashrc`に環境変数を追加します。
```bash
export MACHBASE_HOME=/home/machbase/machbase_home
export PATH="$MACHBASE_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
```
適用します。
```bash
source ~/.bashrc
```
#### 4. データベースの作成
`machadmin -c`は物理インスタンスのデータベースファイルを作成します。SQLの`CREATE DATABASE`で
論理データベースを追加する操作とは区別してください。実行前に`MACHBASE_HOME`、`conf/machbase.conf`、
実際の`DBS_PATH`が新規インストールの対象か確認します。既存データベースがあるというエラーの場合は、
削除・再作成せず、まず対象パスを確認します。
```bash
machadmin -c
# Database created successfully.
```
#### サーバー起動前の設定とライセンス確認
`conf/machbase.conf`の`PORT_NO`と`DBS_PATH`を確認します。別途ライセンスを使用する場合は、
[ライセンスのインストール](../pre-install-preparation/#license)のファイルコピーまたは`machadmin -t`で
インストールし、`machadmin -f`で確認してから起動します。
#### 5. サーバーの起動
```bash
machadmin -u
# Machbase server started successfully.
```
プロセスの確認:
```bash
machadmin -e
```
#### 6. 接続テスト
`machsql`でサーバーに接続します。デフォルトの管理者アカウントは`SYS / MANAGER`です。
```bash
machsql
# Machbase server address (Default:127.0.0.1) :
# Machbase user ID (Default:SYS)
# Machbase User Password :
# MACHBASE_CONNECT_MODE=INET, PORT=5656 EDITION=STANDARD
# Mach>
```
簡単なテストを行います。
```sql
CREATE LOG TABLE install_check (id INTEGER, val DOUBLE);
INSERT INTO install_check (id, val) VALUES (1, 3.14);
SELECT id, val FROM install_check;
DROP TABLE install_check;
```
`id=1`、`val=3.14`の1行が返り、最後のDROPが成功することを確認します。
`install_check`がすでに存在する場合は削除せず、未使用の実習用名に置き換えます。
#### サーバーの終了
インストール確認後、サーバーを停止する必要がある場合のみ実行します。
```bash
machadmin -s
# Machbase server shut down successfully.
```
#### ポートの変更
デフォルトポート(5656)を変更するには、`$MACHBASE_HOME/conf/machbase.conf`の`PORT_NO`を変更するか、
環境変数を設定します。
```bash
export MACHBASE_PORT_NO=7878
```
サーバーを終了した状態で設定を適用し、再起動します。この環境変数は現在のシェルだけに適用されるため、
サービスとして起動する場合はサービスの環境にも反映します。接続には
`machsql -s 127.0.0.1 -P 7878 -u SYS`のように変更したポートを指定します。
---
### Dockerインストール
Dockerイメージではサーバーと実行環境をコンテナーとしてデプロイできます。開発・テスト環境でも、
ホストのDocker Engine、保存ボリューム、ポート、ファイルディスクリプター上限を準備する必要があります。
Dockerを事前にインストールしてください。デプロイチュートリアルは`machbase/machbase`イメージを使用します。
ソースからDockerイメージを直接ビルドした場合は、ローカルイメージ名(`machbase:latest`など)に置き換えます。
#### イメージの確認
```bash
docker pull machbase/machbase
docker image ls machbase/machbase
```
#### コンテナーの実行
```bash
docker create \
--name machbase \
--ulimit nofile=65535 \
-p 5656:5656 \
-v /data/machbase:/home/machbase/machbase/dbs \
machbase/machbase
```
| オプション | 説明 |
|------|------|
| `-p 5656:5656` | ホストSQLポート:コンテナーSQLポートのマッピング |
| `--ulimit nofile=65535` | コンテナー内のサーバーのファイルディスクリプター上限 |
| `-v /data/machbase:...` | データディレクトリをホストに保持するボリュームマウント |
データがコンテナーの書き込み層だけにあると、コンテナー削除時に一緒に削除されます。
実際のデータパスがボリュームに接続されているか確認し、ボリューム自体の削除やディスク障害に備えて
バックアップも準備します。
`docker create`はまだサーバーを起動しません。`/data/machbase`にはコンテナーのサーバー実行アカウントが
書き込める必要があります。既存DBファイルがある場合は、バージョンとインスタンスが合うか確認します。
イメージの実バージョンと`MACHBASE_HOME`パスを確認し、本番では検証済みのイメージタグまたはダイジェストを
固定します。タグなしの公開イメージが常に8.7.0とは考えないでください。
別途ライセンスを使用する場合は、起動前に準備したファイルを次のようにコピーします。
```bash
docker cp /path/to/license.dat machbase:/home/machbase/machbase/conf/license.dat
```
準備ができたらコンテナーを起動します。
```bash
docker start machbase
```
#### コンテナー状態の確認
```bash
docker ps
docker logs machbase
```
#### 接続テスト
##### machsql(コンテナー内部)
```bash
docker exec -it machbase machsql
# Mach>
```
##### ホストからの接続
ホストにmachsqlがインストールされている場合:
```bash
machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER
```
#### コンテナーの終了と再起動
```bash
docker stop machbase
docker start machbase
```
#### ライセンスのインストール
実行中にライセンスを更新する場合は、コンテナーにファイルをコピーしてからライセンスインストールコマンドを
実行します。コンテナーの設定ファイルとライセンスはデータボリュームとは別のため、コンテナー再作成時にも
再適用できるよう元のファイルを保持します。
```bash
docker cp /path/to/license.dat machbase:/tmp/license.dat
docker exec machbase machadmin -t /tmp/license.dat
docker exec machbase machadmin -f
```
---
## Windowsへのインストール
### インストール前の確認
- **対応OS**: 提供されたWindowsパッケージのリリース情報で対応バージョンを確認します。
- **アーキテクチャー**: パッケージのビット数とOSのアーキテクチャーが一致する必要があります。
先に[Windows環境の準備](/ja/dbms/installation-deployment-upgrade/standard-edition/#windows-preparation-environment-windows)を
完了してください。
### インストール方式
| 方式 | 説明 |
|------|------|
| [Windowsパッケージインストール](/ja/dbms/installation-deployment-upgrade/standard-edition/#windows-package) | インストールウィザードで環境変数とショートカットを作成 |
---
### Windows環境の準備
Windowsにインストールする前にファイアウォール設定を確認します。
#### ファイアウォールのポートを開く
Machbaseが使用するポートを、Windowsファイアウォールの受信規則に追加します。
| ポート | プロトコル | 用途 |
|------|---------|------|
| 5656 | TCP | SQLクライアント接続 |
##### 設定方法
1. **コントロールパネル → Windows Defenderファイアウォール → 詳細設定**を開きます。
2. 左ペインの**受信の規則**を選び、右ペインで**新しい規則**をクリックします。
3. 規則の種類に**ポート**を選び、**次へ**をクリックします。
4. **TCP**を選び、**特定のローカルポート**に`5656`を入力して**次へ**をクリックします。
5. **接続を許可する**を選び、**次へ**をクリックします。
6. 接続を許可するネットワークプロファイル(**ドメイン**、**プライベート**、**パブリック**)だけを選び、**次へ**をクリックします。
7. 規則名(例: `Machbase`)を入力し、**完了**をクリックします。
規則の作成後、プロパティのリモートアドレス範囲も実際のクライアントアドレスに制限します。
リモート接続を使用しない環境では、受信許可規則は不要です。
##### PowerShellで設定(管理者権限)
GUIの代わりにPowerShellですばやく設定します。
```powershell
New-NetFirewallRule -DisplayName "Machbase SQL" -Direction Inbound -Protocol TCP -LocalPort 5656 -Action Allow
```
#### Visual C++再頒布可能パッケージ
実行にはVisual C++ Redistributableが必要です。インストーラーでは自動処理される場合がありますが、
問題が発生した場合はMicrosoft公式サイトから最新バージョンを手動インストールしてください。
---
### Windowsパッケージインストール
Windows版はZIPパッケージまたはインストーラー実行ファイルで提供されます。ZIPはアーカイブルートに
`bin\`、`conf\`、`dbs\`、`trc\`などを含み、インストーラーはインストールパス配下に`machbase_home\`を
作成して環境変数と実行ショートカットを生成します。
#### インストール手順
1. Windows配布パッケージをダウンロードします。
2. ZIPパッケージの場合は、目的のインストールディレクトリに展開します。
```cmd
mkdir C:\machbase
tar -xf machbase-SDK-8.7.0.official-WINDOWS-X86-64-release.zip -C C:\machbase
```
3. インストーラーが提供された場合は実行します。開始画面が表示されたら**Next**をクリックします。
4. インストールパスを選びます。デフォルトは`C:\machbase-\`形式です。
変更が必要ならパスを修正して**Next**をクリックします。
5. インストールが進み、完了したら**Next** → **Close**をクリックします。
#### ZIPパッケージの初期化
ZIPを展開した場合は、コマンドプロンプトでそのディレクトリをインストールホームに指定します。
以下は`C:\machbase`へ新規インストールした例です。実際の設定ファイルとライセンスを先に確認し、
既存DBのない新規インスタンスだけで`-c`を実行します。
```cmd
set "MACHBASE_HOME=C:\machbase"
set "PATH=%MACHBASE_HOME%\bin;%PATH%"
machadmin.exe -c
machadmin.exe -f
machadmin.exe -u
machadmin.exe -e
```
上記の`set`は現在のウィンドウに適用されます。他のウィンドウやサービスから実行する場合も、
同じインストールホームと実行ファイルパスを使用する必要があります。インストーラーがすでにデータベースを
作成した場合は、ZIP用の作成コマンドを繰り返さないでください。
#### サーバーの起動と終了
インストーラーを使用すると、デスクトップとスタートメニューにショートカットが作成されます。
- **start Machbase**: `machadmin.exe -u`でサーバーを起動します。
- **stop Machbase**: `machadmin.exe -s`でサーバーを終了します。
- **machsql**: SQLコンソールを起動します。
#### コマンドライン接続
インストール後、コマンドプロンプトで`machsql`を実行してサーバーに接続します。インストーラーを使用した
場合は`<インストールパス>\machbase_home\bin`がシステムの`PATH`に追加されます。ZIPの場合は展開先の
`bin\`を`PATH`に追加するか、フルパスで実行します。
```cmd
machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER
```
デフォルトの管理者アカウント: `SYS` / `MANAGER`
#### インストールパスの構造
ZIPパッケージは展開先直下に`bin\`、`conf\`、`dbs\`、`trc\`などを配置します。
インストーラーはインストールパス配下の`machbase_home\`に同じ構成を作成します。
[パッケージ構成](/ja/dbms/installation-deployment-upgrade/pre-install-preparation/#package)を参照してください。
---
title: "3.3 Cluster Editionのインストールとデプロイ"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/cluster-edition/
language: ja
kind: page
---
# 3.3 Cluster Editionのインストールとデプロイ
Cluster EditionはSQL接続、データ保存、レプリケーション、ノード管理を複数の役割に分けます。
インストール前に各役割をどのホストへ配置するか、どのポートと保存パスを使うかを決めます。
通常のSQL接続はBrokerへ、運用コマンドは該当する管理ノードへ送る必要があります。
## ノードの役割
| ノード | 役割 |
|------|------|
| **Coordinator** | クラスターメタ情報の管理、ノード状態の監視 |
| **Deployer** | パッケージの配布とノード初期化の中継 |
| **Lookup** | 参照データと検索処理 |
| **Broker** | SQLの解析とクエリの分配、クライアントの接続先 |
| **Warehouse** | 実データの保存とクエリ実行 |
以下のYAML例は、3ホストにCoordinator 2台、Deployer 3台、Lookup 2台(master 1台、monitor 1台)、
Broker 2台、Warehouse 2台(1つのレプリケーショングループ)を配置します。
実際のノード数と配置は、可用性、スループット、障害時に残す必要がある容量に基づいて決めます。
## デプロイ方式
| 方式 | 説明 | 適している場合 |
|------|------|------------|
| [machclusterctl](/ja/dbms/installation-deployment-upgrade/cluster-edition/#machclusterctl) | cluster.yamlによる自動デプロイ | 推奨。新規構築 |
| [手動(machcoordinatoradmin)](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin) | Coordinatorコマンドによるノード登録・デプロイ | 細かい制御が必要な場合 |
## インストール手順
1. [Cluster Editionの構成概要](/ja/dbms/installation-deployment-upgrade/cluster-edition/#overview)を理解
2. [環境の準備](/ja/dbms/installation-deployment-upgrade/cluster-edition/#preparation-environment-cluster-edition)(SSH鍵、カーネルパラメーター、NTP)
3. パッケージ・パスと[ライセンス](../pre-install-preparation/#license)の適用方式を準備
4. デプロイ方式を選択してインストール・起動し、ライセンスを確認
5. [インストール検証](/ja/dbms/installation-deployment-upgrade/validation-checklist/)
---
## Cluster Editionの構成概要
役割を分離したCoordinator、Deployer、Lookup、Broker、Warehouseノードで構成されます。
各ノードの役割と相互関係を理解してからデプロイ計画を立ててください。
### ノードの役割の詳細
#### Coordinator
クラスターメタデータ、ノード登録、状態監視を担当します。Primary/Secondaryによる冗長化を検討してください。
稼働中のデータ処理経路と管理経路は分かれていますが、Coordinator障害時に全SQLの継続動作が保証される
わけではありません。他ノードの状態とクライアントへの影響も確認し、検証済みの障害対応手順を使用します。
- 設定ファイル: `$MACHBASE_COORDINATOR_HOME/conf/machbase.conf`
- 管理ツール: `machcoordinatoradmin`
- 主なポート: `CLUSTER_LINK_PORT_NO`、`HTTP_ADMIN_PORT`
デフォルトは`CLUSTER_LINK_PORT_NO=3868`、`HTTP_ADMIN_PORT=5779`です。本章の例では運用中の
ポート競合を避けるため、Coordinatorのlink/adminポートに`5101`/`5102`を明示します。
#### Deployer
Coordinatorの指示に従い、各ノードへパッケージを配布して初期化を中継します。
各ノードホストに1台ずつ配置するか、専用のデプロイサーバーで運用します。
- 管理ツール: `machdeployeradmin`
#### Lookup
参照データと検索処理のためのノードです。構成に応じて`master`、`monitor`、`slave`の役割を指定します。
#### Broker
クライアントのSQL要求を受け取り、解析して適切なWarehouseへ分配します。通常のアプリケーションは
Brokerのアドレスに接続します。Warehouseへの直接接続はレプリケーション状態の比較など管理診断手順だけで
使用し、アプリケーションの接続経路と区別します。Brokerの冗長化を推奨します。
- クライアント接続ポート: デフォルト5656
#### Warehouse
実データを保存してクエリを実行します。同じグループのWarehouse間でデータを複製し、高可用性を提供します。
グループごとに2台以上を推奨します。
### 構成例
```
[クライアント]
│ (SQL, 5656)
▼
[Broker ×2] ──────────────────────────────────────────
│ (クエリ分配)
├─► [Warehouse group1-node1] ◄──レプリケーション──► [Warehouse group1-node2]
└─► [Warehouse group2-node1] ◄──レプリケーション──► [Warehouse group2-node2]
[Coordinator Primary] ◄──HA──► [Coordinator Secondary]
│ (メタ情報管理、ノード監視)
[Deployer]
│
[Lookup master / monitor]
```
### Editionの比較
Standard Editionとの詳細比較は
[Editionの違い](/ja/dbms/core-concepts/concepts-edition/#differences-standard-edition-cluster)を参照してください。
---
## Cluster Editionのインストール環境の準備
デプロイ前に全ノードで次の環境を準備します。
### ファイルディスクリプターの上限
全ノードに次の設定を適用します。
```bash
sudo vi /etc/security/limits.conf
```
```
* hard nofile 65535
* soft nofile 65535
```
サーバー実行アカウントで新しいログインセッションを開き、確認します。サービスマネージャーから起動する場合は、
サービス自体のファイルディスクリプター上限も確認します。
```bash
ulimit -Sn
# 65535
```
### OSユーザーの作成
全ノードに`machbase`アカウントを作成します。
```bash
sudo useradd -m machbase --home-dir /home/machbase
sudo passwd machbase
```
### SSH鍵認証
`machclusterctl`を使用する場合は、デプロイサーバーから全ノードへパスワードなしでSSH接続できる必要があります。
```bash
# デプロイサーバーでSSH鍵を生成(既存なら省略)
ssh-keygen -t rsa -b 4096
# 各ノードに公開鍵を登録
ssh-copy-id machbase@192.168.1.11
```
登録後、パスワードなしで接続できるか確認します。
```bash
ssh machbase@192.168.1.11 'hostname'
```
### ネットワークのカーネルパラメーター
以下はネットワークバッファの調整例であり、全サーバーに適用する必須値ではありません。
現在のカーネル設定、メモリ使用量、ネットワークのボトルネックを先に測定します。値を増やした後は
スループットだけでなくメモリと遅延も比較し、効果を確認した項目だけを永続化します。
```bash
sudo sysctl -w net.core.rmem_default=33554432
sudo sysctl -w net.core.wmem_default=33554432
sudo sysctl -w net.core.rmem_max=268435456
sudo sysctl -w net.core.wmem_max=268435456
sudo sysctl -w 'net.ipv4.tcp_rmem=262144 33554432 268435456'
sudo sysctl -w 'net.ipv4.tcp_wmem=262144 33554432 268435456'
sudo sysctl -w 'net.ipv4.tcp_mem=8388608 8388608 8388608'
```
永続化するには`/etc/sysctl.conf`に追加します。
### 時刻同期(NTP)
全ノードのシステム時刻が一致する必要があります。NTPまたは`chrony`で同期してください。
```bash
# chronyの使用例
sudo systemctl enable chronyd
sudo systemctl start chronyd
chronyc tracking
```
タイムサーバーを使用できない隔離されたインストール環境では、初期時刻を直接設定できます。
次の値は書式例なので実際の現在時刻に置き換えてください。手動設定だけではノード間の時刻差を継続的に
補正できないため、本番投入前に時刻同期経路を用意します。
```bash
sudo date -s "2025-01-02 12:34:56"
```
### ポートの予約
各ノードでMachbaseが使用するポートを予約します。
```bash
current=$(cat /proc/sys/net/ipv4/ip_local_reserved_ports)
ports=5101-5110,5201-5202,5301-5302,5401,5500-5503,5656
sudo sysctl -w net.ipv4.ip_local_reserved_ports="${current:+$current,}$ports"
```
既存の予約ポートは上書きせず、カンマで区切って統合します。クラスター構成に応じてポート範囲を調整してください。
Cluster link、Coordinator/Deployerの管理、サービス、Warehouseのレプリケーション管理ポートなどを
すべて含める必要があります。
---
## machclusterctlによるデプロイ
`machclusterctl`は1つの`cluster.yaml`でクラスター全体を自動デプロイ・管理するツールです。
SSHで各ノードにリモート接続し、パッケージ配布、初期化、起動・終了を一括処理します。
### 前提条件
- Primary Coordinatorをインストールするホストでコマンドを実行し、そのホストからパッケージと
SSH秘密鍵を読み取れる必要があります。
- Primaryホストから全対象ホストへSSH鍵認証が設定されている必要があります。
- 各ノードの`home_path`と`dbs_path`の親パスに作成・書き込み権限が必要です。
- 別のライセンスが必要な場合は、自動起動前に配布パッケージとライセンス適用手順を準備します。
YAMLに任意のライセンスプロパティは追加しません。
- [Cluster Editionのインストール環境の準備](/ja/dbms/installation-deployment-upgrade/cluster-edition/#preparation-environment-cluster-edition)の完了
### 作業手順
| 段階 | ドキュメント |
|------|------|
| 1. cluster.yamlの作成 | [cluster.yamlの作成](/ja/dbms/installation-deployment-upgrade/cluster-edition/#machclusterctl-cluster-yaml) |
| 2. YAMLの妥当性検査 | [YAMLの検証](/ja/dbms/installation-deployment-upgrade/cluster-edition/#machclusterctl-validation-yaml) |
| 3. 初回インストールと起動 | [初回インストール](/ja/dbms/installation-deployment-upgrade/cluster-edition/#machclusterctl-initial) |
| 4. 状態確認 | [初回インストールと状態確認](/ja/dbms/installation-deployment-upgrade/cluster-edition/#machclusterctl-initial) |
| 5. 以降の構成変更 | [Cluster運用](/ja/dbms/operations-configuration-recovery/cluster/) |
| 6. 障害時の復旧 | [Clusterのトラブルシューティング](/ja/dbms/troubleshooting/cluster/) |
---
### cluster.yamlの作成
`cluster.yaml`はインストールするノード構成とパスを宣言します。以下のアドレスは例のため実ホストに
置き換えます。`origin_path`はコマンドを実行するPrimary Coordinatorホストから読み取るアーカイブ、
`home_path`と`dbs_path`は該当ノードホスト上のパスです。`deployer`はそのノードを配置・制御する
Deployerを参照します。
#### ファイル構造の例
```yaml
version: "1"
cluster:
name: mc-prod
hosts:
node1:
address: machbase@192.168.1.10
node2:
address: machbase@192.168.1.11
node3:
address: machbase@192.168.1.12
package:
name: machbase
origin_path: /home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz
ssh:
key_file: /home/machbase/.ssh/id_rsa
defaults:
coordinator:
home_path: /home/machbase/coordinator
cluster_link_port: 5101
http_admin_port: 5102
deployer:
home_path: /home/machbase/deployer
cluster_link_port: 5201
http_admin_port: 5202
lookup:
home_path: /home/machbase/lookup
cluster_link_port: 5301
broker:
home_path: /home/machbase/broker
cluster_link_port: 5401
service_port: 5656
warehouse:
home_path: /home/machbase/warehouse
cluster_link_port: 5501
service_port: 5500
coordinators:
- alias: coord-primary-1
host: node1
role: primary
- alias: coord-secondary-1
host: node2
role: secondary
deployers:
- alias: deployer-1
host: node1
- alias: deployer-2
host: node2
- alias: deployer-3
host: node3
lookup:
- alias: lookup-master-1
host: node1
deployer: deployer-1
type: master
- alias: lookup-monitor-1
host: node2
deployer: deployer-2
type: monitor
brokers:
- alias: broker-1
host: node1
deployer: deployer-1
dbs_path: /data/machbase/broker-1/dbs
- alias: broker-2
host: node2
deployer: deployer-2
warehouse_groups:
- name: group1
nodes:
- alias: warehouse-group1-1
host: node2
deployer: deployer-2
dbs_path: /data/machbase/warehouse-group1-1/dbs
- alias: warehouse-group1-2
host: node3
deployer: deployer-3
dbs_path: /data/machbase/warehouse-group1-2/dbs
```
#### 主な項目の説明
| 項目 | 説明 |
|------|------|
| `version` | YAMLスキーマバージョン。現在は`"1"`を使用します。 |
| `cluster.name` | クラスター名。`destroy`の確認などで使用します。 |
| `cluster.hosts` | ノードから参照するホスト別名とSSH接続先。`address`は`user@host`形式です。 |
| `cluster.package.name` | Coordinatorへ登録するパッケージ名。 |
| `cluster.package.origin_path` | `install`、`apply`、`upgrade`の入力に使用するパッケージアーカイブのパス。 |
| `cluster.package.registered_path` | `export`が記録するCoordinatorのパッケージ保存先の観測パス。実行入力には使用しません。 |
| `cluster.ssh.key_file` | 対象サーバーへの接続に使用する秘密鍵パス。パスワードフィールドは使用しません。 |
| `cluster.defaults` | ノードタイプ別の`home_path`、`cluster_link_port`、`service_port`のデフォルト値。 |
| `cluster.coordinators` | Coordinatorノード一覧。`role`は`primary`または`secondary`。 |
| `cluster.deployers` | Deployerノード一覧。 |
| `cluster.lookup` | Lookupノード一覧。`type`は`master`、`monitor`、`slave`。 |
| `cluster.brokers` | Brokerノード一覧。クライアントSQL接続ポートは`service_port`。 |
| `cluster.warehouse_groups` | Warehouseグループとグループ別ノード一覧。 |
#### 推奨構成
- Coordinator: 2台(Primary + Secondary HA)
- Deployer: 1台以上
- Lookup: `master` 1台、`monitor` 1台以上
- Broker: 2台以上(負荷分散)
- Warehouseグループ: グループごとに2台(レプリケーションによる高可用性)
同じサーバーに同タイプのノードを2台以上配置する場合は、2台目以降の`home_path`とポートを明示し、
競合を避けます。
CoordinatorとDeployerの管理ポートには`http_admin_port`を使用します。
BrokerとWarehouseには任意で`dbs_path`を指定します。`dbs_path`はノードがインストールされるサーバーの
データファイルパスで、省略時は`machcoordinatoradmin --add-node`のデフォルト`DBS_PATH`動作に従います。
既存の`cluster.package.path`は後方互換入力として使用できますが、新しいYAMLでは`origin_path`を使用します。
`http_admin_port`はCoordinatorとDeployerだけに使用します。Broker、Lookup、Warehouseには
HTTPポートフィールドを指定しません。
作成後に妥当性を検査します。
---
### YAMLの検証
`cluster.yaml`を実際のインストールに使用する前に妥当性を検査します。`validate`はYAML構文、必須値、
別名、ポート競合、トポロジーの関係を静的に検査します。
#### 検証コマンド
```bash
machclusterctl validate -f cluster.yaml
```
#### 検証項目
| 項目 | 説明 |
|------|------|
| YAML構文 | ファイルの解析エラー |
| 環境変数の置換 | `${VAR}`または`${VAR:-default}`式を解釈できるか |
| 必須フィールド | クラスター名、ホスト、パッケージ、ノード別の必須値の欠落 |
| 別名 | ノード別名の重複 |
| ポート競合 | 同じホスト内の宣言ポートの競合 |
| トポロジー | Primary Coordinator、Lookup master/monitor、Deployerの参照関係 |
#### 出力例
```text
Validation passed.
```
エラーがあれば、メッセージの項目を修正して再検証します。
#### インストール前の実行計画確認
新規インストール前にSSH接続、パッケージの存在、リモートディレクトリ権限まで確認するには、
`install --dry-run --verbose`を使用します。
```bash
machclusterctl install -f cluster.yaml --dry-run --verbose
```
インストール後の構成変更を検証する場合は`apply --dry-run`を使用します。現在のクラスター状態とYAMLの
差を計算して実行計画を表示し、実際のリモート変更は行いません。
```bash
machclusterctl apply -f cluster.yaml --dry-run --verbose
```
#### 一般的なエラーと解決方法
| エラー | 原因 | 解決方法 |
|------|------|------|
| `field ... not found` | 非サポートのYAMLキー | 現行スキーマの`cluster.*`項目に修正 |
| `required field ...` | 必須値の欠落 | メッセージのフィールドを追加 |
| `duplicate alias` | ノード別名の重複 | 全ノードの別名を一意に変更 |
| `port conflict` | 同一ホストで同じポートを使用 | 競合ポートを別に指定。ホームパスだけの変更では解決しない |
| `deployer ... not found` | Lookup/Broker/Warehouseが存在しないDeployerを参照 | `deployer`値をDeployerの別名またはホスト:ポートに修正 |
---
### 初回インストール
`cluster.yaml`の作成と検証が完了したら、インストール計画を確認してクラスターをインストールします。
#### 1. クラスターのインストール
各ノードへのパッケージ配布と初期化の前に、実行計画と事前検査の結果を確認します。
```bash
machclusterctl install -f cluster.yaml --dry-run --verbose
```
問題がなければ実際にインストールします。
```bash
machclusterctl install -f cluster.yaml --yes --verbose
```
このコマンドは次の処理を自動実行します。
1. 各ノードへのパッケージコピーと展開
2. 各ノードの`machbase.conf`作成とポート設定
3. Coordinatorデータベースの初期化
4. ノード登録(Coordinatorに各ノードを追加)
#### 2. クラスターの起動
`install`はCoordinator、Deployer、Lookup、Broker、Warehouseを準備して起動します。
インストール後にクラスター全体を再起動する必要がある場合だけ、次のコマンドを使用します。
```bash
machclusterctl start
```
#### 3. 状態確認
```bash
export MACHBASE_COORDINATOR_HOME=/home/machbase/coordinator
machclusterctl status
```
1台のサーバーで複数のCoordinatorホームを切り替えて確認する場合は、直接指定します。
```bash
machclusterctl status --coordinator /home/machbase/coordinator
```
出力は`machcoordinatoradmin --cluster-status-full --verbose`形式です。以下は出力列を示す一部の行の例で、
YAMLの全ノード一覧ではありません。CoordinatorとBrokerは`primary`、`leader`など役割別の状態を取るため、
全行が`normal`かではなく、登録ノード数と役割別の目標・実際の状態が一致するかを確認します。
```
+-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+
| Node Type | Node Name | Group Name | Group State | Desired & Actual State | RP State | Disk(%) (00/00) | Ping(μs) |
+-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+
| coordinator | coord-1(192.168.1.10:5101) | Coordinator | normal | primary | primary | ----------- | --------------- | 214 |
| deployer | deployer-1(192.168.1.10:5201) | Deployer | normal | running | running | ----------- | --------------- | 100 |
| broker | broker-1(192.168.1.11:5401) | Broker | normal | leader | leader | ----------- | --------------- | 100 |
| warehouse | wh-g1-1(192.168.1.13:5501) | group1 | normal | normal | normal | running | 26.9 | 100 |
+-------------+--------------------------------+--------------------------------+--------------------------------+-------------------------------+-------------+-----------------+----------+
```
#### 4. クライアント接続テスト
BrokerノードのIPとポートに接続します。
```bash
machsql -s 192.168.1.11 -P 5656 -u SYS -p MANAGER
# Mach>
```
#### クラスターの終了
```bash
machclusterctl stop
```
---
### インストール後の運用
初回インストールと接続検証後のノード構成変更、追加・削除、状態復旧は
[Cluster運用](../../operations-configuration-recovery/cluster/)に従います。障害原因の分類と
復旧判断は[Clusterのトラブルシューティング](../../troubleshooting/cluster/)を参照してください。
## machcoordinatoradminによる手動デプロイ
`machclusterctl`を使用できない場合はCoordinatorとDeployerを直接準備し、パッケージとノードを登録します。
自動デプロイ済みの環境で以下の作成コマンドを再実行しないでください。手動例はYAMLとは別構成です。
役割別に実行場所を変えてコマンドを実行します。
| ホスト | 役割 |
|---|---|
| `192.168.1.10` | Primary Coordinator、Deployer、Lookup master |
| `192.168.1.11` | Deployer、Lookup monitor、Broker |
| `192.168.1.13` | Deployer、Warehouse group1の最初のノード |
| `192.168.1.14` | Deployer、Warehouse group1のレプリカノード |
| `192.168.1.20` | 任意のSecondary Coordinator |
同一ホストの役割ごとにホームとポートを分けます。Deployerはデータ処理ノードをインストールする各ホストで
準備し、以下の`--deployer`アドレスも対象ホストに合わせます。
### 手動デプロイの手順
1. [パッケージの準備と登録](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin-package) — 完全パッケージのインストールと軽量パッケージの登録準備
2. [Coordinator / Deployerのインストール](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin-coordinator-deployer) — 主要な管理ノードを起動
3. [パッケージ登録](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin-package) — 稼働中のCoordinatorへ軽量パッケージを登録
4. [Lookup / Broker / Warehouseのインストール](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin-lookup-broker-warehouse) — データ処理ノードを登録・起動
5. [全体状態の確認](/ja/dbms/installation-deployment-upgrade/cluster-edition/#manual-machcoordinatoradmin-lookup-broker-warehouse) — 登録・起動後の初回状態検証
### machclusterctlとの違い
| 項目 | machclusterctl | 手動デプロイ |
|------|---------------|----------|
| 設定方式 | cluster.yamlの単一ファイル | 各ノードのmachbase.confを直接編集 |
| パッケージ配布 | 自動リモートコピー | Coordinator/Deployerは直接インストール、Broker/WarehouseはDeployerが配布 |
| ノード登録 | 自動 | `machcoordinatoradmin --add-node`を手動実行 |
| 一括起動・終了 | `machclusterctl start/stop` | ノードごとに個別実行 |
手動デプロイは柔軟ですが、ミスの可能性も高くなります。新規構築には`machclusterctl`を推奨します。
---
### パッケージの準備と登録
Cluster Editionの手動デプロイでのパッケージ準備・登録手順です。CoordinatorとDeployerには完全パッケージを
インストールして環境変数を設定します。BrokerとWarehouse用の軽量パッケージはCoordinatorの起動後に登録します。
#### パッケージの種類
Cluster Editionには2種類のパッケージがあります。
| パッケージ | 対象ノード | 特徴 |
|--------|-----------|------|
| 完全パッケージ | Coordinator、Deployer | 全実行ファイルを含む |
| 軽量パッケージ(lightweight) | Broker、Warehouse | データ処理に必要なファイルだけを含み、小容量 |
ファイル名の例:
- 完全: `machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz`
- 軽量: `machbase-cluster-8.7.0.official-LINUX-X86-64-release-lightweight.tgz`
#### CoordinatorとDeployerへのパッケージ配布
完全パッケージをCoordinatorとDeployerノードにコピーして展開します。
##### Coordinatorノード
```bash
# Coordinatorノードで実行
mkdir -p /home/machbase/coordinator
scp machbase@package-host:/path/to/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz /home/machbase/
tar zxf /home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz -C /home/machbase/coordinator
```
##### Deployerノード
```bash
mkdir -p /home/machbase/deployer
scp machbase@package-host:/path/to/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz /home/machbase/
tar zxf /home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz -C /home/machbase/deployer
```
この段階ではBrokerとWarehouseへ軽量パッケージを直接展開しません。Coordinatorへ軽量パッケージを登録すると、
後で`--add-node`で指定したDeployerが対象ノードの`--home-path`へパッケージを配布します。
#### Coordinatorへのパッケージ登録
CoordinatorからBrokerとWarehouseを起動するには、Coordinatorへの軽量パッケージ登録が必要です。
CoordinatorとDeployerをインストールし、Coordinatorが稼働中の状態で次のコマンドを実行します。
```bash
$MACHBASE_COORDINATOR_HOME/bin/machcoordinatoradmin --add-package=machbase \
--file-name="/home/machbase/machbase-cluster-8.7.0.official-LINUX-X86-64-release-lightweight.tgz"
```
登録したパッケージは、後でBrokerとWarehouseを`--add-node`で登録する際に`--package-name=machbase`で
参照します。
#### 環境変数の設定
`package-host`と`/path/to/`は実際のパッケージ保存場所に置き換えます。CoordinatorとDeployerを同じホストで
管理する場合も、別々のシェルで役割に合う環境を使用します。以下は各シェルに適用する値で、サービスや
ログイン初期化ファイルにも同じ値を反映します。
```bash
# Coordinatorノード
export MACHBASE_COORDINATOR_HOME=/home/machbase/coordinator
export MACHBASE_HOME=$MACHBASE_COORDINATOR_HOME
export PATH=$MACHBASE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$MACHBASE_HOME/lib:$LD_LIBRARY_PATH
```
```bash
# 別のDeployer管理シェル
export MACHBASE_DEPLOYER_HOME=/home/machbase/deployer
export MACHBASE_HOME=$MACHBASE_DEPLOYER_HOME
export PATH="$MACHBASE_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
```
---
### Coordinator / Deployerのインストール
パッケージ配布後、Coordinatorを先にインストール・起動してからDeployerを登録します。
#### Coordinatorのインストール
##### 1. machbase.confの設定
`$MACHBASE_COORDINATOR_HOME/conf/machbase.conf`を編集します。
```bash
vi $MACHBASE_COORDINATOR_HOME/conf/machbase.conf
```
主な設定:
```
CLUSTER_LINK_HOST = 192.168.1.10 # このノードのIP
CLUSTER_LINK_PORT_NO = 5101
HTTP_ADMIN_PORT = 5102
```
##### 2. メタデータベースの作成とサービス起動
```bash
machcoordinatoradmin -c
machcoordinatoradmin -u
```
##### 3. 自身をCoordinatorノードとして登録
```bash
machcoordinatoradmin --add-node="192.168.1.10:5101" \
--node-type=coordinator \
--http-admin-port=5102
```
##### 4. 登録の確認
```bash
machcoordinatoradmin --cluster-status
```
#### Secondary Coordinatorのインストール(任意)
高可用性のためSecondary Coordinatorを追加します。
Secondaryノードにパッケージを配布して`machbase.conf`を設定し、先に**Primary Coordinatorで**ノードを
登録します。
```bash
# Primary Coordinatorで先に登録
machcoordinatoradmin --add-node="192.168.1.20:5101" \
--node-type=coordinator \
--http-admin-port=5102
# 次にSecondaryノードで起動(--primaryでPrimaryを指定)
machcoordinatoradmin -u --primary=192.168.1.10:5101
```
Secondaryの起動前に、必ずPrimaryでノード登録を完了する必要があります。
#### Deployerのインストール
手動構成表の各Deployerホストでこの手順を行います。以下の設定の`CLUSTER_LINK_HOST`は、そのホスト自身の
IPに置き換えます。他ホストのアドレスをそのままコピーすると、ノードの通信アドレスと実際の実行場所が
異なってしまいます。
##### 1. machbase.confの設定
```
CLUSTER_LINK_HOST = 192.168.1.10 # DeployerノードのIP
CLUSTER_LINK_PORT_NO = 5201
HTTP_ADMIN_PORT = 5202
```
##### 2. 起動
```bash
machdeployeradmin -c
machdeployeradmin -u
```
##### 3. CoordinatorへのDeployerノード登録
全Deployerが起動したら、Primary Coordinatorの管理シェルで登録します。
```bash
machcoordinatoradmin --add-node="192.168.1.10:5201" \
--node-type=deployer \
--http-admin-port=5202
machcoordinatoradmin --add-node="192.168.1.11:5201" \
--node-type=deployer --http-admin-port=5202
machcoordinatoradmin --add-node="192.168.1.13:5201" \
--node-type=deployer --http-admin-port=5202
machcoordinatoradmin --add-node="192.168.1.14:5201" \
--node-type=deployer --http-admin-port=5202
```
---
### Lookup / Broker / Warehouseのインストール
CoordinatorとDeployerの準備後、Lookup、Broker、WarehouseをCoordinatorに登録して起動します。
BrokerとWarehouseの登録前に、軽量パッケージをCoordinatorへ`--add-package`で登録する必要があります。
#### Lookupノード
Lookup masterとmonitorをそれぞれ登録して起動します。次の例はPrimaryホストとBrokerホストへ配置し、
各ホストのDeployerを使用します。同じホームが既存のLookupで使用中でないことを確認します。
```bash
machcoordinatoradmin --add-node="192.168.1.10:5301" \
--node-type=lookup \
--lookup-type=master \
--deployer="192.168.1.10:5201" \
--home-path="/home/machbase/lookup"
machcoordinatoradmin --add-node="192.168.1.11:5301" \
--node-type=lookup \
--lookup-type=monitor \
--deployer="192.168.1.11:5201" \
--home-path="/home/machbase/lookup"
machcoordinatoradmin --startup-node="192.168.1.10:5301"
machcoordinatoradmin --startup-node="192.168.1.11:5301"
```
#### Brokerのインストール
##### 1. 登録パラメーターの確認
Broker設定ファイルは`--add-node`時に生成され、Deployer経由で対象ノードへ配布されます。
登録前にクラスター通信ポートとサービスポートを確定します。BrokerにHTTP管理ポートは指定しません。
```
CLUSTER_LINK_HOST = 192.168.1.11 # BrokerノードのIP
CLUSTER_LINK_PORT_NO = 5401
PORT_NO = 5656 # クライアント 接続ポート
```
##### 2. Coordinatorへのノード登録
Coordinatorノードで実行します。
```bash
machcoordinatoradmin --add-node="192.168.1.11:5401" \
--node-type=broker \
--deployer="192.168.1.11:5201" \
--package-name=machbase \
--home-path="/home/machbase/broker" \
--dbs-path="/data/machbase/broker_dbs" \
--port-no=5656
```
| パラメーター | 説明 |
|---------|------|
| `--add-node` | 登録するノードのIP:CLUSTER_LINK_PORT_NO |
| `--node-type` | `broker` / `warehouse` / `lookup` |
| `--deployer` | そのノードをインストール・制御するDeployerのIP:CLUSTER_LINK_PORT_NO |
| `--package-name` | Coordinatorに登録したパッケージ名 |
| `--home-path` | ノードのホームディレクトリ |
| `--dbs-path` | Broker/Warehouseのデータファイルパス。省略時はデフォルト`DBS_PATH` |
| `--port-no` | クライアントまたはノードのサービスポート |
| `--replication` | Warehouseのレプリケーション管理アドレス。`host:port`形式 |
##### 3. ノードの起動
Coordinatorで該当ノードを起動します。
```bash
machcoordinatoradmin --startup-node="192.168.1.11:5401"
```
#### Warehouseのインストール
Warehouseノードはグループ単位で構成します。同じグループ内のノード間でデータを複製します。
##### 1. 登録パラメーターの確認
Warehouse設定ファイルは`--add-node`時に生成され、Deployer経由で対象ノードへ配布されます。
登録前にクラスター通信ポート、サービスポート、レプリケーション管理アドレスを確定します。
```
CLUSTER_LINK_HOST = 192.168.1.13
CLUSTER_LINK_PORT_NO = 5501
PORT_NO = 5500
```
##### 2. ノードの登録
```bash
machcoordinatoradmin --add-node="192.168.1.13:5501" \
--node-type=warehouse \
--deployer="192.168.1.13:5201" \
--package-name=machbase \
--home-path="/home/machbase/warehouse_g1_1" \
--dbs-path="/data/machbase/warehouse_g1_1_dbs" \
--port-no=5500 \
--replication=192.168.1.13:5502 \
--group=group1 \
--no-replicate
machcoordinatoradmin --add-node="192.168.1.14:5501" \
--node-type=warehouse \
--deployer="192.168.1.14:5201" \
--package-name=machbase \
--home-path="/home/machbase/warehouse_g1_2" \
--dbs-path="/data/machbase/warehouse_g1_2_dbs" \
--port-no=5500 \
--replication=192.168.1.14:5502 \
--group=group1
```
別途`--add-group`コマンドは使用しません。Warehouseグループ名は各Warehouseノードの登録時に
`--group`で指定します。
##### 3. ノードの起動
```bash
machcoordinatoradmin --startup-node="192.168.1.13:5501"
machcoordinatoradmin --startup-node="192.168.1.14:5501"
```
#### 全体状態の確認
全ノードの登録後に状態を確認します。
```bash
machcoordinatoradmin --cluster-status
```
Coordinator、Lookup、Broker、Warehouseが各役割に合う正常状態で表示されれば、クラスターは正常に
稼働しています。Coordinatorは`primary`、Brokerは`leader`、Warehouseは`normal`、`sync-active`、
`sync-standby`などで表示されます。
#### 初回接続の確認
Brokerのネイティブポートに接続し、`SELECT CURRENT_DATABASE();`とサンプル検索を実行します。
初回インストール検証後の個別ノードの起動・終了と状態復旧は
[Cluster運用](../../operations-configuration-recovery/cluster/)と
[Clusterのトラブルシューティング](../../troubleshooting/cluster/)を使用してください。
---
title: "3.4 アップグレード"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/upgrade/
language: ja
kind: page
---
# 3.4 アップグレード
アップグレードは実行ファイルの交換だけでなく、既存のデータ、設定、アプリケーションが新バージョンで
同じ意味で動作するかを確認する作業です。まず対応するバージョン間の経路を確認し、復元可能なバックアップと
サービス再開基準を準備します。以下の8.7.0パッケージ名とパスは、提供された実際の配布物に合わせます。
## アップグレード前の確認事項
- 現在と対象のバージョンの互換性を確認します。マイナーバージョンが異なるとDBファイル形式が変わる場合があります。
- アップグレード前にバックアップします。[バックアップ方法](/ja/dbms/operations-configuration-recovery/backup-restore-mount/#backup)を参照してください。
- 実行中のINSERT・APPENDクライアントを確認します。
### 8.7.0アップグレードの事前確認
8.5から8.7.0にアップグレードする場合は、バイナリ交換前に次の依存関係を調査し、対応する方式へ移行します。
1. 廃止された`HTTP_AUTH`、`HTTP_ENABLE`、`HTTP_MAX_MEM`、`HTTP_PORT_NO`、`RS_CACHE_*`、
`STREAM_THREAD_COUNT`、`STREAM_WAIT_MS`設定を現在のファイルで探し、サポート一覧と照合します。
廃止設定は削除し、継続設定は保持します。特にClusterの`HTTP_ADMIN_PORT`は現行の管理ポートのため、
`HTTP_*`という理由で一緒に削除しないでください。
2. `/machbase`、`/machiot`を呼ぶアプリケーションは、対応SDKを使用するバックエンドへ移行します。
3. `STREAM_*`プロシージャと`FLUSH RESULT_CACHE`を実行するSQL・運用スクリプトを変更します。
4. `machcli.h`と`MachCLI*()`を使用するC/C++アプリケーションをMachbase SQLCLIまたはODBCに移行します。
SQLCLIとODBCは異なるAPI集合です。
5. WebAdmin/MWAに依存する運用手順・ダッシュボードは、コマンドラインツールまたは別アプリケーションへ移行します。
全廃止項目と継続機能は
[バージョンと互換性](/ja/dbms/reference/support-scope-constraints/compatibility-version/#removed-features-870)を参照してください。
## アップグレード経路
| Edition | 方式 | リンク |
|--------|------|------|
| Standard Edition | サーバー終了後にパッケージを交換 | [Standard Editionのアップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#standard-edition) |
| Cluster Edition | Broker/Warehouseを順次アップグレード | [オンラインアップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#cluster-edition-online) |
| Cluster Edition | 全体停止 | [全体停止アップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#cluster-edition-full-stop) |
Cluster Editionではデータ可用性の要件に応じてオンライン方式または全体停止方式を選びます。
---
## Standard Editionのアップグレード
サーバーを終了し、パッケージを交換して再起動します。物理DBファイルをそのまま開くことがサポートされる
バージョン間経路だけに適用します。データ変換やエクスポート・インポートが必要な経路は、
該当リリースの移行手順を先に実行します。
### アップグレード前の準備
1. **バックアップ**: 対応するBACKUPコマンドでバックアップを作成し、別環境で復元可能か確認します。
実行中のデータディレクトリを単純にコピーしただけで復旧可能なバックアップを確保したとは判断しません。
2. **クライアント接続の終了**: 実行中のAppendまたはINSERTをすべて完了します。
3. **現在のバージョン確認**:
```bash
machbased -v
```
### アップグレード手順
#### 1. サーバーの終了
```bash
machadmin -s
# Machbase server shut down successfully.
```
#### 2. 既存パッケージと設定の保管
実行ファイルとライブラリだけでなく、現在の設定とライセンスも別の場所に保管します。
以下のパスに以前のバックアップがないことを確認して実行します。
```bash
cp -a "$MACHBASE_HOME/bin" "$MACHBASE_HOME/bin.bak"
cp -a "$MACHBASE_HOME/lib" "$MACHBASE_HOME/lib.bak"
cp -a "$MACHBASE_HOME/conf" "$MACHBASE_HOME/conf.bak"
```
**データディレクトリ(`dbs/`)と別途指定した`DBS_PATH`は保持します。** 上記のコピーは実行ファイルと
設定の保管であり、DBバックアップの代わりにはなりません。新バージョンがデータを変更した後に旧実行ファイルを
戻すだけで復旧できるとは考えず、検証済みのバックアップ復元経路を使用します。
#### 3. 新パッケージの展開
新パッケージは別の作業ディレクトリに展開し、構成と設定の変更点を先に確認します。
```bash
upgrade_stage=$(mktemp -d)
tar zxf machbase-SDK-8.7.0.official-LINUX-X86-64-release.tgz -C "$upgrade_stage"
```
展開だけでは既存インストールの実行ファイルは変わりません。以下は`bin/`、`lib/`、`include/`を含む
Standard tarballから実行ファイル・ライブラリ・ヘッダーを反映する例です。先にサーバー終了を確認し、
コマンドが失敗した場合は次の起動段階に進まないでください。
```bash
(
set -e
test -n "$MACHBASE_HOME"
test -x "$upgrade_stage/bin/machbased"
test -d "$upgrade_stage/lib"
test -d "$upgrade_stage/include"
test -d "$MACHBASE_HOME/bin"
test -d "$MACHBASE_HOME/lib"
test -d "$MACHBASE_HOME/include"
cp -a "$upgrade_stage/bin/." "$MACHBASE_HOME/bin/"
cp -a "$upgrade_stage/lib/." "$MACHBASE_HOME/lib/"
cp -a "$upgrade_stage/include/." "$MACHBASE_HOME/include/"
"$MACHBASE_HOME/bin/machbased" -v
)
```
既存の`conf/machbase.conf`、ライセンス、実際の`DBS_PATH`のデータは保持し、新設定項目を既存設定に
マージします。コピーは同名の配布ファイルを交換しますが、旧バージョンにしかないファイルは自動削除しません。
SDKやプラグインは新バージョンに合うファイルを明示的に選び、追加の交換対象と削除項目はリリース情報で確認します。
出力されたバイナリバージョンと設定の確認が完了してからサーバーを起動します。
#### 4. サーバーの起動
```bash
machadmin -u
# Machbase server started successfully.
```
#### 5. バージョンの確認
```bash
machbased -v
# サーバーへ接続
machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER
```
```sql
SELECT EDITION, BINARY_DB_MAJOR_VERSION, BINARY_DB_MINOR_VERSION FROM V$VERSION;
```
### 注意事項
- `dbs/`ディレクトリを削除・初期化(`machadmin -d`)しないでください。
- マイナーバージョン間のアップグレードではDBファイルの移行が必要な場合があります。必ずリリースノートを確認してください。
- Windowsでは新パッケージまたはインストーラー適用前にMachbaseサービスを停止します。
---
## Cluster Editionのアップグレード
サービス停止の可否に応じて2つの方式から選びます。
| 方式 | サービス停止 | 適している状況 |
|------|-----------|------------|
| [オンラインアップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#cluster-edition-online) | Broker/Warehouseを順次再起動 | BrokerとWarehouseだけを交換する本番環境 |
| [全体停止アップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#cluster-edition-full-stop) | あり | メンテナンス時間帯を確保できる場合、メジャーバージョン変更 |
### 共通の事前注意事項
- アップグレード中はDDLまたはDELETEを実行しないでください。
- アップグレード中にノードの追加・起動・終了・削除を並行して行わないでください。
- オンラインアップグレードはBrokerとWarehouseが対象です。Coordinator、Deployer、Lookupも交換する場合は全体停止方式を使用します。
- アップグレード前のバックアップを推奨します。
---
### オンラインアップグレード
稼働中のクラスターでBrokerとWarehouseを順次アップグレードします。Coordinator、Deployer、Lookupを
含む全バイナリの交換が必要な場合は
[全体停止アップグレード](/ja/dbms/installation-deployment-upgrade/upgrade/#cluster-edition-full-stop)を使用します。
#### アップグレード手順
##### 1. cluster.yamlのパッケージ変更
`cluster.package.name`と`cluster.package.origin_path`を新パッケージに変更します。
パッケージ内容が変わる場合は、パッケージ名とアーカイブ名も一意な新しい名前に変更します。
```yaml
cluster:
package:
name: machbase-v8.7.0
origin_path: /home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz
```
`registered_path`は`machclusterctl export`が記録するCoordinatorのパッケージ保存先パスです。
アップグレードするアーカイブの指定には`origin_path`を使用します。
##### 2. 実行計画の確認
```bash
machclusterctl upgrade -f cluster.yaml --online --dry-run --verbose
```
##### 3. オンラインアップグレードの実行
```bash
machclusterctl upgrade -f cluster.yaml --online --yes --verbose
```
`--online`を省略してもオンラインモードになりますが、運用手順を明確にするため明示を推奨します。
##### 4. 全体状態の確認
```bash
machclusterctl status
```
#### 手動アップグレードの補足
`machcoordinatoradmin --upgrade-node`を直接使用する場合は、対象ノードとパッケージ名をともに指定します。
```bash
machcoordinatoradmin --upgrade-node=192.168.1.11:5401 --package-name=machbase-v8.7.0
```
オンラインの対象はBrokerとWarehouseに限定します。Brokerが1台しか残っていないときにそのBrokerを
アップグレードすると、その間クライアント接続が切れる場合があります。
オンラインモードはクラスター全体の停止を省略する方式であり、無停止を保証するHA対応のローリング
アップグレードではありません。Warehouseグループが一時的に読み取り専用になる場合があるため、
アプリケーションの再接続・再試行と書き込み遅延を検証する必要があります。プロトコル互換性が変わる場合や、
全役割のバイナリを合わせる必要がある場合は全体停止方式を使用します。
全対象ノードの役割状態とバージョンを確認してから、代表的な検索・入力とレプリケーション状態まで検証します。
---
### 全体停止アップグレード
クラスターを完全に終了し、全ノードを一括アップグレードします。Coordinator、Deployer、Lookupを含む
全バイナリの交換が必要な場合や、DBファイル形式の変更を伴う場合に使用します。
#### アップグレード手順
##### 1. クライアント接続の終了
全INSERT・APPEND・SELECT操作が完了したことを確認します。
##### 2. cluster.yamlのパッケージ変更
`cluster.package.name`と`cluster.package.origin_path`を新パッケージに変更します。
アップグレード前にノード追加・削除・ポート変更などのトポロジー変更を残してはいけません。
変更がある場合は先に`apply`で反映してからアップグレードします。
`machclusterctl upgrade --full-stop`はCoordinatorとDeployerを含む全ノードホームに同じパッケージを
交換反映します。そのため`origin_path`には`machcoordinatoradmin`と`machdeployeradmin`を含む
完全なClusterパッケージを指定します。
##### 3. 実行計画の確認
```bash
machclusterctl upgrade -f cluster.yaml --full-stop --dry-run --verbose
```
##### 4. 全体停止アップグレードの実行
```bash
machclusterctl upgrade -f cluster.yaml --full-stop --yes --verbose
```
`machclusterctl`はクラスター全体の停止を前提に、パッケージを一時準備パスへ展開してから
ノードホームへ交換反映します。
#### 手動デプロイの補足
手動デプロイ環境で直接交換する場合は、Coordinatorに新パッケージを登録します。
```bash
machcoordinatoradmin --add-package=machbase-v8.7.0 \
--file-name=/home/machbase/packages/machbase-cluster-8.7.0.official-LINUX-X86-64-release.tgz
```
Warehouse → Broker → Lookup → Deployer → Coordinatorの順で終了します。
```bash
machcoordinatoradmin --shutdown-node=192.168.1.13:5501
machcoordinatoradmin --shutdown-node=192.168.1.14:5501
machcoordinatoradmin --shutdown-node=192.168.1.11:5401
machcoordinatoradmin --shutdown-node=192.168.1.10:5301
machdeployeradmin --shutdown
machcoordinatoradmin --shutdown
```
各ノードホームを新パッケージに交換する際は、既存の`conf/machbase.conf`、`dbs/`、`meta/`、`package/`を
保持します。別の作業パスに新パッケージを展開し、保持対象パスを除いて交換します。
Coordinator → Deployer → Lookup → Broker → Warehouseの順で起動します。
```bash
machcoordinatoradmin --startup
machdeployeradmin --startup
machcoordinatoradmin --startup-node=192.168.1.10:5301
machcoordinatoradmin --startup-node=192.168.1.11:5401
machcoordinatoradmin --startup-node=192.168.1.13:5501
machcoordinatoradmin --startup-node=192.168.1.14:5501
```
再起動後、BrokerとWarehouseのパッケージメタデータを新パッケージ名に同期します。
```bash
machcoordinatoradmin --upgrade-node=192.168.1.11:5401 --package-name=machbase-v8.7.0
machcoordinatoradmin --upgrade-node=192.168.1.13:5501 --package-name=machbase-v8.7.0
machcoordinatoradmin --upgrade-node=192.168.1.14:5501 --package-name=machbase-v8.7.0
```
##### 5. 状態の確認
```bash
machclusterctl status
```
ノード状態に加え、Broker接続、代表データの検索・入力、レプリケーション、ライセンス、設定値を確認してから
サービスを再開します。[インストール検証](../validation-checklist/)の結果を変更前の記録と比較し、
検証完了まで旧パッケージ・設定とバックアップを保持します。
#### 注意事項
- メジャーバージョンのアップグレードではDBファイル形式が変わる場合があります。必ずリリースノートを確認し、事前にバックアップしてください。
- `conf/machbase.conf`、`dbs/`、`meta/`、`package/`を削除・初期化しないでください。
---
title: "3.5 インストール検証チェックリスト"
url: https://docs.machbase.com/ja/dbms/installation-deployment-upgrade/validation-checklist/
language: ja
kind: page
---
# 3.5 インストール検証チェックリスト
インストール検証はプロセスの生存確認だけでは完了しません。正しいバージョンと設定のサーバーに
実際のクライアントが接続し、権限の範囲内でデータを書き込み・検索できる必要があります。
以下をサーバー状態 → 接続 → バージョン・ライセンス → SQL → Clusterのレプリケーションの順に確認します。
各結果に実行ホスト、インストールホーム、接続先アドレス・ポート、時刻、エラーを記録します。
アップグレードの場合は変更前の記録と比較してください。`SYS`/`MANAGER`は初期実習の接続例であり、
実際のアカウントに置き換えます。実習テーブル名が既存業務オブジェクトと重複しないことも先に確認します。
## Standard Editionのチェックリスト
### 1. サーバープロセスの確認
```bash
machadmin -e
# Machbase server is running with PID().
```
プロセスを直接確認することもできますが、別のインストールホームで実行されたサーバーと区別する必要があります。
`MACHBASE_HOME`が検査対象インスタンスを指すことを確認します。
```bash
ps -ef | grep machbased | grep -v grep
```
### 2. ポートのリスニング確認
```bash
ss -tlnp | grep 5656
# LISTEN 0 128 0.0.0.0:5656 ...
```
現在のOSに合うポート確認ツールを使用します。例の`5656`は実際のSQLポートに置き換え、受信アドレスが
意図したインターフェースか確認します。リスナー確認とリモートクライアントの接続成功は別の検査のため、
アプリケーションを実行するホストでも接続を試します。
### 3. machsqlの接続テスト
```bash
machsql -s 127.0.0.1 -P 5656 -u SYS -p MANAGER
# MACHBASE_CONNECT_MODE=INET, PORT=5656 EDITION=STANDARD
# Mach>
```
ローカル接続が成功してリモート接続だけ失敗する場合は、アドレス・ポート、リスナー設定、ファイアウォールを
確認します。認証エラーはユーザー名・認証方式・有効期限を確認し、接続成功後のオブジェクトアクセスエラーは
現在のデータベースとSQL権限を別途確認します。
### 4. バージョンの確認
```sql
SELECT * FROM V$VERSION;
SELECT CURRENT_DATABASE();
```
### 5. ライセンスの確認
```sql
SELECT ID, ISSUE_DATE, TYPE, VIOLATE_STATUS FROM V$LICENSE_INFO;
```
`VIOLATE_STATUS`が0か確認し、インストールしたライセンスの種類・期間が運用計画に合うか確認します。
違反状態の場合は`VIOLATE_MSG`とサーバーログで原因を確認します。
### 6. 基本クエリのテスト
```sql
CREATE LOG TABLE check_test (id INTEGER, ts DATETIME);
INSERT INTO check_test (id, ts) VALUES (1, NOW);
SELECT id, ts FROM check_test;
DROP TABLE check_test;
```
入力した`id=1`の1行と時刻が返り、DROPが成功することを確認します。この検査は基本的なLOG入力経路だけを
確認します。実際のサービスでTAG・TRANSACTION・Appendなどを使用する場合は、該当テーブルとSDKでも
代表的な入力・検索を実行します。
## Cluster Editionの追加チェックリスト
### 7. クラスターノードの状態確認
```bash
machcoordinatoradmin --cluster-status
# デプロイ記録のノード数と役割別状態を比較
```
### 8. Brokerの接続テスト
```bash
machsql -s 192.168.1.11 -P 5656 -u SYS -p MANAGER
```
```sql
SELECT * FROM V$NODE_STATUS;
```
Coordinatorの`primary`、Brokerの`leader`、Warehouseのレプリケーション状態など、正常状態の表示は
役割ごとに異なります。全ノードを単一の文字列と比較せず、目標状態と実際の状態、グループ構成、アドレスが
デプロイ記録と合うか確認します。
### 9. データレプリケーションの確認
まずBroker経由の入力・検索を確認し、次にWarehouseグループのレプリケーション状態を確認します。
Brokerで1行が検索できるだけでは、全レプリカの同期を証明できません。
```sql
-- Broker経由でデータを入力
CREATE LOG TABLE cluster_check_test (id INTEGER, ts DATETIME);
INSERT INTO cluster_check_test (id, ts) VALUES (1, NOW);
-- Brokerで入力結果を確認
SELECT COUNT(*) FROM cluster_check_test;
```
Warehouseへの直接SQL接続は通常のアプリケーション経路ではなく、レプリケーション診断用の管理手順です。
`machcoordinatoradmin --cluster-status`で同じレプリケーショングループのactive・standbyピアを確認し、
必要な場合のみ各ピアのネイティブポートへ管理アカウントで接続して同じ検索結果を比較します。
異なるWarehouseグループの全ノードが同じ行を持つとは考えないでください。
検証後はBroker接続でテーブルを削除します。
```sql
DROP TABLE cluster_check_test;
```
---
## 完了基準と問題発生時の対応
サーバー・接続・権限・代表SQLと必要なレプリケーション検査がすべて通れば、サービスの引き継ぎを進めます。
永続性の検証が必要な場合は、専用の検証環境にデータを残し、正常な再起動の前後で結果を比較します。
業務データのあるサーバーを、単純なインストール確認のために再初期化しないでください。
失敗時は最初のエラーと関連ログを保持し、失敗した段階から原因を絞り込みます。
- サーバーログ: `$MACHBASE_HOME/trc/machbase.trc`
- [運用・障害診断](/ja/dbms/operations-configuration-recovery/diagnosis-observability/)を参照
---
title: "4. テーブルタイプとスキーマ設計"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/
language: ja
kind: section
---
# 4. テーブルタイプとスキーマ設計
この章では、保存するデータの意味と変更・クエリ要件を、Machbase DBMS のテーブルと列へ具体化します。
稼働を確認したら、まず1行に何を保存するかを決めます。慣れたタイプを先に選んですべてのデータを
当てはめると、履歴、更新範囲、保持ポリシーの要件が衝突することがあります。
各タイプの役割を初めて学ぶ場合は、[データモデルの概念](/ja/dbms/core-concepts/concepts/)を先に読んでください。
この章では概念を実際のスキーマと検証可能な設計に結び付けます。
## 設計の出発点
テーブル名より先に、1行の意味を文章で定義します。「1つのセンサーの1回の計測」、
「設備状態の変化イベント」、「1台の機器の現在の設置情報」は異なる単位です。
同じ設備のデータでも、保存上の役割は異なります。
次の問いに答えると、テーブルを選ぶ根拠が得られます。
| 設計上の問い | 決定事項 |
|---|---|
| 1行は何を表すか | 計測、イベント、現在状態、参照データのどれを保存するか |
| 対象をどう識別するか | タグ名、業務キー、重複収集の識別基準 |
| 時刻や軸は何を意味するか | 計測時刻、受信時刻、距離・位置 |
| 値をどう解釈するか | 単位、型の範囲、精度、NULL・欠測処理 |
| どの変更が必要か | 追記、過去値の補正、キー変更、削除範囲 |
| どのクエリが多いか | タグ・時間範囲、条件検索、キー検索、集計、結合 |
| どれだけ保持するか | 元データ・集計・参照履歴の期間と再起動後の復旧 |
| 失敗時に何を戻すか | テーブル・API 別のトランザクション範囲と再試行・再構築手順 |
データサイズや入力頻度だけでタイプを決めないでください。同じ行の値が同じ観測やイベントを表すことを
確認し、関連データは共通識別子で結合できるようにします。結合キーがあることと、DBMS がすべての
業務上の関係を自動的に強制することは別です。対応する制約をタイプ別に確認します。
## この章の構成
| 順序 | 節 | 設計結果 |
|-----:|---|---|
| 4.1 | [テーブルタイプの選択](./table-types-selection-type/) | 変更・クエリ・永続性・Edition の要件に合うタイプ |
| 4.2 | [スキーマオブジェクトの定義](./schema-objects-definition/) | 列と型、識別子、デフォルト・制約、インデックス、VIEW |
| 4.3 | [データ変更ポリシー](./alter-data-mutation-policy/) | 許可する補正・削除と失敗処理の範囲 |
| 4.4 | [アンチパターン](./table-types-patterns-type-anti/) | 要件に合わない選択を修正する根拠 |
| 4.5 | [モデリングパターン](./patterns-modeling/) | 履歴・状態・参照データを組み合わせる具体例 |
4.1でタイプを選び、4.2と4.3で構造と変更方針を定義します。4.4のアンチパターンを点検し、
4.5のパターンを実データに適用します。比較表は出発点です。実際の SQL と条件は、
リンクしたテーブル別の文書とリファレンスで確認します。
## 設備監視の例
温度、アラーム、機器情報、画面表示用の状態をすべて同じ方式で保存する必要はありません。
| データ | 1行の意味 | 検討する保存方法 |
|---|---|---|
| 温度履歴 | 1センサーが特定時刻に測定した値 | タグ・時間範囲クエリと集計用の TAG |
| アラーム履歴 | 特定時刻のアラームイベント | 追記型イベント用の LOG |
| 機器の参照データ | 機器の名前・場所・許容基準 | LOOKUP、または複数変更をトランザクションにまとめる場合の TRANSACTION |
| 画面用の現在状態 | 再計算できる最新状態 | 元データと再構築経路がある場合の VOLATILE |
この表は例であり、固定の正解ではありません。複数項目が1イベントに含まれる場合や、更新・保持要件が
異なる場合は、別の設計が適切なこともあります。TRANSACTION は Standard Edition の対応も確認します。
温度履歴に最新の機器情報を結合すると、結果は現在の名前や場所で解釈されます。計測時点の場所や
許容基準が必要なら、元データに保存するか参照データの変更履歴を設計します。現在状態キャッシュも
更新する場合、元データ入力とキャッシュ更新を1トランザクションと考えず、失敗後の再構築方法を用意します。
## 小さなデータで設計を検証
運用規模へ拡大する前に、代表データと頻出クエリで次を確認します。
1. 正常値だけでなく NULL、欠測、境界値、重複・遅延データを入力します。
2. 元データと集計のクエリが同じ時刻基準・単位・NULL 方針を使うか確認します。
3. 補正・削除・再入力後の結果と、他の行や集計への影響を比較します。
4. 再起動後も保持するデータと再生成する状態を分け、復旧順序を確認します。
5. 入力量、クエリ範囲、同時実行数を増やし、スループット・遅延・保存領域を測定します。
入力エラー、旧スキーマを使うアプリケーション、再起動後の復旧も、通常経路と併せて設計します。
スキーマ変更前には既存データとビュー・ROLLUP・クライアントの依存関係を確認し、
必要なら新テーブルへ移行して検証後に切り替えます。
実装は[テーブル別利用ガイド](/ja/dbms/)と[開発とアプリケーション連携](/ja/dbms/development-tools-integration/)、
測定は[性能チューニング](/ja/dbms/performance-tuning/)に進みます。
---
title: "4.1 テーブルタイプの選択"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/table-types-selection-type/
language: ja
kind: page
---
# 4.1 テーブルタイプの選択
タイプの選択を誤ると性能低下や機能制限につながるため、設計初期にデータの性質に合うタイプを決めます。
- **[タイプ選択ガイド](/ja/dbms/data-modeling-table-design/table-types-selection-type/#selection-decision)**
- **[タイプ比較表](/ja/dbms/data-modeling-table-design/table-types-selection-type/#comparison-tag-log-rdb-volatile-lookup)**
- **[TRANSACTION と LOOKUP の比較](/ja/dbms/data-modeling-table-design/table-types-selection-type/#comparison-rdb-vs-lookup)**
役割と保存の概念は[データモデルの概念](../../core-concepts/concepts/#time-series)を参照してください。
同じデータでも、履歴を蓄積するか現在状態を更新するかで適切なタイプが変わります。
変更・クエリ・永続性の要件を併せて検討します。
### 選択前に記述するデータの説明
テーブル名より先に、1行が表す事実を1文で記述します。同じ設備でも、1回の温度計測、
現在の運転状態、1件の保守作業は異なる単位であり、キーと変更方法も異なります。
| 設計上の問い | 設備監視で決める内容 |
|---|---|
| 1行は何か | センサーの1回の計測か、設備の現在状態か |
| 何で検索するか | センサー名と発生時刻、設備 ID、保守作業番号 |
| 値はどう変わるか | 履歴の追加、誤値の補正、現在行の上書き |
| 同時に確定する変更があるか | 保守作業登録と部品数量変更を1トランザクションにまとめるか |
| どれだけ保持するか | 元データ・集計の期間と、再起動後の再生成可否 |
| 規模はどの程度か | タグ数、毎秒行数、行サイズ、参照データとインデックスのメモリ |
例えば温度履歴は TAG、アラームイベントは LOG、設備コード表は LOOKUP が候補です。
部品在庫変更と作業登録を同時に確定するなら Standard Edition の TRANSACTION を検討します。
現在状態キャッシュは元データから再構築できる場合に VOLATILE へ分離できます。
1テーブルへ統合する前に、行の意味と失敗時の復旧方法を整合させます。
## タイプ選択ガイド
次の流れで候補を絞り、比較表で DML、トランザクション、メモリ、Edition の要件を確認します。
参照データでも複数変更を1トランザクションへまとめる場合は、LOOKUP ではなく TRANSACTION を検討します。
### 選択フロー
```
センサー/機器の計測値か?
├── YES → 時間軸か? YES → TAG TABLE (BASETIME)
│ 距離軸か? YES → TAG TABLE (BASEDISTANCE)
└── NO ↓
イベント/ログ/パケットか?(追記専用)
├── YES → LOG TABLE
└── NO ↓
コード表/参照データか?(繰り返し検索・更新)
├── YES → LOOKUP TABLE
└── NO ↓
再起動時に破棄できるインメモリ状態/キャッシュか?
├── YES → VOLATILE TABLE
└── NO ↓
一般的なリレーショナル業務データ(UPDATE/DELETE/SELECT/INSERT がすべて必要)
└── TRANSACTION TABLE
```
### 主な判断基準
| 問い | タイプ |
|------|------|
| 時間または距離に基づく計測値か | TAG |
| 元イベントを追記し、古い範囲だけを削除するか | LOG |
| PRIMARY KEY が必要な参照データを繰り返し検索・更新するか | LOOKUP |
| 再起動でデータが消えてもよいか | VOLATILE |
| 一般的なリレーショナル業務(INSERT/UPDATE/DELETE/SELECT)か | TRANSACTION |
### 注意事項
- イベントごとに一意なタグ名を付けると、タグ数とメタデータが増え続けます。
繰り返し計測する対象がないイベントには LOG を検討します。
- LOG は UPDATE と一般条件 DELETE ができないため、更新が必要なデータには不適切です。
保持・整理用の `BEFORE`、`OLDEST`、`EXCEPT` DELETE を使用します。
- TRANSACTION は Standard Edition 専用です。Cluster では小規模 LOOKUP または外部 RDBMS を使用します。
- VOLATILE のデータは再起動で消失します。
## タイプ比較表
### 機能比較
| 項目 | TAG | LOG | TRANSACTION | VOLATILE | LOOKUP |
|------|-----|-----|-----|----------|--------|
| DDL | `CREATE TAG TABLE` | `CREATE LOG TABLE` | `CREATE TABLE` / `CREATE TRANSACTION TABLE` / `CREATE TXN TABLE` | `CREATE VOLATILE TABLE` | `CREATE LOOKUP TABLE` |
| 主用途 | センサー・計測 | イベント・ログ | リレーショナル業務 | 一時集計 | コード・参照データ |
| INSERT | O | O | O | O | O |
| UPDATE | O(Standard、タグ/BASETIME 条件) | X | O | O | O |
| DELETE | O(BEFORE/条件/全体) | O(BEFORE/OLDEST/EXCEPT/全体) | O | O(PK 一致/全体) | O(一般条件/全体) |
| PRIMARY KEY | 必須 | X | 任意 | 任意 | 必須 |
| BASETIME | 必須(時間軸) | X | X | X | X |
| _arrival_time | X | 自動追加 | X | X | X |
| インデックス | タグ・軸アクセス、対応するセカンダリ | BITMAP/KEYWORD/LSM | BTREE PK + セカンダリ | キー・セカンダリ | キー・セカンダリ |
| 永続性 | O | O | O | X(メモリ) | O |
| Cluster Edition | O | O | X | O | O |
Append API の対応は、テーブルだけでなく SDK と入力経路でも変わります。
[SDK Append 対応表](../../development-tools-integration/sdk-support-scope/#append-table-type-matrix)で
使用するドライバーとテーブルの組み合わせを確認します。
### ストレージ特性
| 項目 | TAG | LOG | TRANSACTION | VOLATILE | LOOKUP |
|------|-----|-----|-----|----------|--------|
| ストレージ | 列指向 | 列指向 | 行指向(リレーショナル) | メモリ | 永続保存 + 全行がメモリに常駐 |
| 容量検討基準 | タグ数・元データ・ROLLUP・保持期間 | 元データ・検索インデックス・保持期間 | 行・インデックス・トランザクション負荷 | 全行とインデックスのメモリ | 全行とインデックスのメモリ、再起動時のロード時間 |
インメモリテーブルが小さいとは、固定の行数を意味しません。行幅、可変長値、セカンダリインデックスを
含めて実メモリ使用量を測定します。ディスク型でも圧縮率やサーバー仕様だけで性能は保証されないため、
代表的な入力とクエリを同時に実行します。
### TRANSACTION の制約
TRANSACTION には次の制約があります。
- **Cluster Edition 非対応**: Standard Edition 専用。
- **最小列数**: 1列以上。
## TRANSACTION と LOOKUP の比較
両方ともリレーショナルデータを保存しますが、対象規模と機能が異なります。
### 比較表
| 項目 | TRANSACTION | LOOKUP |
|------|-----------|--------------|
| DDL | `CREATE TRANSACTION TABLE` | `CREATE LOOKUP TABLE` |
| PRIMARY KEY | 任意 | 必須 |
| INSERT | O | O |
| UPDATE(WHERE あり) | O | O |
| UPDATE(WHERE なし) | O(全行) | X |
| DELETE | O | O |
| 明示的トランザクション | 複数文を COMMIT/ROLLBACK で制御 | 参加せず、文ごとに変更 |
| インデックス | BTREE PK + セカンダリ | メモリ上のキー・セカンダリ |
| データ規模 | ディスク容量とトランザクション負荷で検証 | 参照データの検索・更新負荷で検証 |
| JOIN 対象 | O | O |
| Cluster Edition | X | O |
### 選択ガイド
**TRANSACTION を選ぶ場合**
- 明示的トランザクションとリレーショナル DML が必要。
- UPDATE・DELETE・INSERT・SELECT がすべて必要な一般的ワークロード。
- PRIMARY KEY なしで多様な列の組み合わせを検索。
- Standard Edition 環境。
**LOOKUP を選ぶ場合**
- コード表と参照データ。
- PRIMARY KEY 検索と単一行 UPDATE/DELETE が必要。
- Cluster Edition でも使用。
- 参照データをリアルタイムに更新。
### 例
```sql
-- LOOKUP: 国コード表(PK 検索と条件付き UPDATE)
CREATE LOOKUP TABLE country_code (
code VARCHAR(4) PRIMARY KEY,
name VARCHAR(64)
);
INSERT INTO country_code VALUES ('KR', 'Republic of Korea');
UPDATE country_code SET name = 'Korea' WHERE code = 'KR';
SELECT code, name FROM country_code WHERE code = 'KR';
-- TRANSACTION: 注文履歴(大規模、一般 UPDATE/DELETE 対応)
CREATE TRANSACTION TABLE order_history (
order_id LONG PRIMARY KEY,
item_id INTEGER,
qty INTEGER,
amount DECIMAL(18,2)
);
INSERT INTO order_history VALUES (12345, 501, 1, 12000.00);
UPDATE order_history SET qty = 10 WHERE order_id = 12345;
SELECT order_id, qty, amount FROM order_history WHERE order_id = 12345;
DELETE FROM order_history WHERE order_id = 12345;
SELECT COUNT(*) FROM order_history WHERE order_id = 12345;
```
最初の SELECT は変更後の国名、注文 SELECT は数量 `10`、最後の COUNT は `0` を返します。
この例の `amount` は数量変更と別に維持する金額で、自動再計算されません。実際の注文モデルでは
単価・数量・合計の関係と、一緒に変更する列を明示します。終了後、例で作ったテーブルだけを
`DROP TABLE` で削除します。
---
title: "4.2 スキーマオブジェクトの定義"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/schema-objects-definition/
language: ja
kind: page
---
# 4.2 スキーマオブジェクトの定義
テーブル、列、インデックス、VIEW の設計時に決定する事項をまとめます。SQL 構文とオプションは
重複掲載せず、[SQL 構文リファレンス](/ja/dbms/reference/sql/syntax/)を正本とします。
- **[テーブルの作成と削除](#create-delete)**
- **[テーブル変更](#alter)**
- **[列とデータ型の選択](#selection-type-column-data-types)**
- **[制約とデフォルト値](#constraints-defaults-condition)**
- **[インデックス設計](#index-create-delete)**
- **[VIEW 設計](#create-view)**
## テーブルの作成と削除
先に[テーブルタイプの選択](../table-types-selection-type/)を完了します。そのタイプに応じて
テーブル名、列、キー、制約、インデックス、VIEW を定義します。
### 行の単位と列の役割
1テーブル内で行の単位を統一します。設備の日次要約と秒単位の元データを同じ意味の行として
混在させると、`COUNT` や `AVG` を解釈しにくくなります。元データと集計には、それぞれ明確な
行の単位とクエリ名を定めます。
| 列の役割 | 例 | 設計原則 |
|---|---|---|
| 対象の識別 | `sensor_id`, `equipment_id` | 表示名とは別の安定した値 |
| 発生基準 | `measured_at`, `event_time` | 発生時刻か受信時刻かを明示 |
| 計測値 | `temperature_c`, `pressure_kpa` | 単位、有効範囲、補正方法を定義 |
| 品質 | `quality_code` | 欠測、計測失敗、有効な0を区別 |
| 参照属性 | 場所、設備タイプ | タグメタデータか別の参照表で管理するか選択 |
外部設備コードなど既存の業務キーは自然キー、別途発行する番号はサロゲートキーです。コード変更や
複数収集元での再利用がある場合は識別範囲を明確にするか、サロゲートキーを検討します。自動増分番号は
生成順序の値であり、発生時刻や重複のない収集を自動保証しません。TAG の名前は計測行ではなくタグを識別します。
テーブル名は英字で始め、英字・数字・アンダースコアを使います。予約語やシステムオブジェクトと
紛らわしい名前は避けてください。削除前に依存する VIEW、インデックス、ROLLUP、保持ポリシーを確認します。
タイプ別の作成例は次を参照してください。
- [TAG テーブル作成](/ja/dbms/tag-table-usage/create-alter-drop/)
- [LOG テーブル作成](/ja/dbms/log-table-usage/create-alter-drop/)
- [TRANSACTION テーブル](/ja/dbms/rdb-table-usage/)
- [LOOKUP テーブル](/ja/dbms/lookup-table-usage/)
- [VOLATILE テーブル](/ja/dbms/volatile-table-usage/)
## テーブル変更
列の追加・削除・名前変更・型変更の対応は、タイプとデータ有無によって異なります。
運用テーブルを変える前に、次の順で判断します。
1. 対象 Edition とタイプが該当 `ALTER TABLE` に対応するか確認します。
2. 既存データ、インデックス、VIEW、アプリケーションの列順序依存を確認します。
3. 運用と同じスキーマ・データ量で実行時間とロックの影響を測定します。
4. 戻すのが難しい場合、新テーブルを作成し、検証後に切り替えます。
列追加後は、既存行と新規入力行をそれぞれ検索し、NULL・DEFAULT の結果を確認します。
すべてのテーブルで既存行が DEFAULT になるわけではありません。VOLATILE の既存行や TAG メタデータの
自動登録行には別の規則があります。[ARRAY の DEFAULT 規則](/ja/dbms/reference/sql/types/array/#default와-기존-row)
を含め、対象タイプの DDL 仕様を確認してください。
アプリケーションのデプロイとスキーマ変更の順序も定めます。対応経路では列リストを明示し、
位置に依存する Append・バインドを新スキーマと照合します。移行時は行数だけでなく、キー別件数、
時間範囲、NULL 比率、代表集計も比較し、切り替え中の新規行の欠落・重複への対応を定めます。
正確な対応と構文は [ALTER TABLE リファレンス](/ja/dbms/reference/sql/syntax/)と
[テーブルタイプ別サポート](/ja/dbms/reference/support-scope-constraints/table-types-type/)を参照してください。
## 列とデータ型の選択
実際の値範囲と演算に基づき、適切な最小の型を選びます。表示形式と保存型を混同しないでください。
| データ | 検討する型 | 注意点 |
| --- | --- | --- |
| 整数の計測値・コード | `SHORT`・`INTEGER`・`LONG` 系 | NULL 予約値と範囲 |
| 浮動小数点の計測値 | `FLOAT`・`DOUBLE` | 精度、集計誤差、NULL 予約値 |
| 正確な小数計算が必要な値 | `DECIMAL` | precision・scale・丸め規則を先に定義 |
| 時刻 | `DATETIME` | 表現範囲とタイムゾーンをクライアント・セッション方針と設計 |
| 短い文字列 | `VARCHAR` | 最大長とエンコーディング |
| 長い本文 | `TEXT` | 対応タイプ、ソート・集計制約、インデックスコスト |
| ネットワークアドレス | `IPV4`・`IPV6` | 文字列ではなくアドレス型を検討 |
| 構造化文書 | `JSON` | サイズ、列への昇格基準、タイプ別対応 |
| バイナリ | `BINARY` | タイプによって可変長・固定長が異なる |
| 固定個数の数値 | 数値 `ARRAY` | 要素の型・長さ、要素 NULL と全体 NULL の区別 |
`VARCHAR(n)` の長さはバイト数で、韓国語や絵文字では文字数と異なります。整数型は一部の境界値を
NULL 用に予約するため、プログラミング言語の整数範囲をそのまま使えません。FLOAT・DOUBLE も
正の最大値を NULL と認識します。型の小ささより、有効範囲と演算の意味を優先します。
### 正確な小数が必要な値: DECIMAL
金額、税率、精算値など10進の正確さが必要なら `DECIMAL` を使います。誤差を許容し広い指数範囲を
必要とする計測には `FLOAT`・`DOUBLE` を使います。違いは保存サイズではなく値の意味です。
丸め結果を業務にそのまま使う値には DECIMAL を選びます。
設計時に次を決めます。
| 決定事項 | 内容 |
|---|---|
| precision | 有効数字の総桁数、1~65 |
| scale | 小数桁数、0~30、precision 以下 |
| 省略時 | `DECIMAL` は `DECIMAL(10,0)`、`DECIMAL(M)` は `DECIMAL(M,0)` |
scale を超える小数は、入力時に最も近い値へ丸め、ちょうど半分なら0から遠ざかる方向へ丸めます。
保存時に確定するため業務規則と一致するか確認します。precision を超える値は切り詰めや浮動小数点変換ではなく
エラーになるため、桁数には余裕を持たせます。
`SUM`、`AVG`、`MIN`、`MAX`、`GROUP BY`、`ORDER BY`、`DISTINCT` は正確な計算経路を使います。
一方、パーセンタイルや高度な統計など、exact DECIMAL 経路がない演算は DOUBLE へ変換し、近似値となります。
正確さが必要な集計と参考用の統計を区別します。
アプリケーション側で浮動小数点を経由すると、保存型に関係なく精度を失います。JDBC は `BigDecimal`、
Python は `decimal.Decimal`、ODBC は `SQL_NUMERIC` など、10進表現または文字列で渡します。
宣言、インデックス、クライアントの対応は
[DECIMAL と NUMERIC 固定小数点型](/ja/dbms/reference/sql/types/decimal-numeric-fixed-point/)を参照してください。
### 構造化文書: JSON
収集元でキーが異なる、または項目が増える追加属性には `JSON` が適しています。スキーマ変更なしに
項目を追加できるためです。一方、`WHERE` や `GROUP BY` に頻繁に使う値は別の列に昇格します。
JSON は主キーにできず、LOOKUP は JSON パスインデックスをサポートしません。
1文書は最大32,768バイト、JSON パスは最大512バイトです。元のペイロード全体を保存するより、
クエリに必要な属性を格納するために使います。
| テーブルタイプ | JSON 列 | 確認事項 |
|---|:---:|---|
| TAG・LOG・TRANSACTION | O | JSON 関数とパスクエリに対応 |
| LOOKUP | O | 一般列として対応、JSON パスインデックスは非対応 |
| VOLATILE | X | JSON 列を作成不可 |
クエリには `->` と `JSON_EXTRACT_*` を使います。`JSON_SET` 系は変更後の文書を返す関数であり、
列へ保存するには対象テーブルの `UPDATE` 制約に従います。LOG は行の `UPDATE` に対応しません。
TAG METADATA では既存の JSON 列を参照して更新できますが、Standard Edition の TAG DATA UPDATE
では既存行の列を参照する SET 式を使用できません。入力時に文書を完成させるか、
対象に適した更新方法を選択します。関数別の対応は
[JSON のテーブルタイプ別サポート](/ja/dbms/reference/sql/types/table-types-type-support-scope-json/)を参照してください。
### 型の選択前に確認する制約
| 型 | 設計時の確認事項 |
|---|---|
| `TEXT` | LOG と Standard Edition の TRANSACTION だけで対応。LOG の TEXT は `ORDER BY`・`GROUP BY` に使えず、`MODIFY COLUMN` で VARCHAR に変換できない。ソート・集計値は別の VARCHAR・数値列に保存。 |
| `BINARY` | LOG は可変長で最大64MB、TAG は固定長 `BINARY(n)` で1~32,767バイト。LOOKUP・VOLATILE は非対応。 |
| `DATETIME` | 1970-01-01~2262-04-11をナノ秒精度で保存。期限や無期限を表すため任意の遠い未来時刻を入れない。 |
| `ARRAY` | 固定長の1次元数値配列。要素数は1~1024。全体 NULL と要素 NULL を区別。 |
全範囲とタイプ別対応は[データ型リファレンス](/ja/dbms/reference/sql/types/)を基準に確認します。
## 制約とデフォルト値
`PRIMARY KEY`、`NOT NULL`、`DEFAULT` の対応はタイプごとに異なります。TAG の `PRIMARY KEY` は
タグ識別子、LOOKUP・VOLATILE・TRANSACTION の `PRIMARY KEY` は行識別と更新経路を決定します。
NULL は未知または欠けた値で、0や空の区間とは異なります。計測失敗を DEFAULT 0 に置き換えると
平均や正常判定が歪みます。`COUNT(*)` は行数、`COUNT(value)` はその列が非 NULL の行数なので、
サンプル数を報告する際に区別します。
デフォルト値は省略入力への方針であり、妥当性検証の代わりではありません。テーブルにない制約は
収集・業務アプリケーションで検証します。外部キーなど他 DBMS の制約を名前だけで対応と判断せず、
[TRANSACTION のサポート範囲](/ja/dbms/reference/support-scope-constraints/rdb/)を確認します。
`_ARRIVAL_TIME` や `_RID` などのシステム列を業務キーに使わないでください。公開されたクエリ上の
意味が必要な場合だけ参照し、保存構造や生成方式には依存しません。
## インデックス設計
インデックスはクエリコストを下げますが、入力・保存コストを増やします。
代表クエリを記述し、条件に一致する行の比率(選択性)を確認します。全設備の月平均と、1台の設備の
特定注文検索ではアクセスが異なります。すべてのフィルター・結合列を索引化せず、`EXPLAIN` と
実測時間を比較して有効なインデックスを残します。
- 時間範囲とタグ識別子で十分な TAG クエリには、最初から追加インデックスを作りません。
- LOG の頻出フィルター列は、計画と選択性を測定してから索引化を検討します。
- LOOKUP・VOLATILE・TRANSACTION はキー検索と結合条件を基準に設計します。
- 長いテキストの単語検索には、そのタイプが対応する `KEYWORD` を検討します。
作成・削除構文と対応タイプは[インデックス SQL リファレンス](/ja/dbms/reference/sql/syntax/)を参照してください。
## VIEW 設計
VIEW は繰り返すクエリに名前を付けますが、結果自体は保存しません。意図しない時間範囲の固定や
不要な全列の読み出しを避け、元テーブル・列の変更前に依存 VIEW を確認します。
頻出の列リストや単位変換を VIEW で一貫して提供できます。ただし作成だけでデータがコピーされたり、
クエリコストが下がったりするわけではありません。過去イベントと最新参照表を結合した VIEW では、
参照表変更で過去の結果も変わる場合があります。発生時点の属性が必要なら、バージョン別参照情報や
元の行に記録した属性を使います。
VIEW の作成・クエリ・削除と制約は[VIEW SQL リファレンス](/ja/dbms/reference/sql/syntax/)を参照してください。
---
title: "4.3 データ変更ポリシー"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/alter-data-mutation-policy/
language: ja
kind: page
---
# 4.3 データ変更ポリシー
`UPDATE`、`DELETE`、`TRUNCATE` のサポートはタイプごとに異なります。このページではモデル選択に
必要な方針をまとめます。正確な構文と制約はリンク先の SQL リファレンスを基準にしてください。
変更ポリシーは、更新できるかだけでなく、誰がどの範囲を変え、失敗時にどこまで戻せるかを定めます。
現在状態の更新、元の計測値の補正、スキーマ変更、保持期限による削除を別々の処理として区別します。
## テーブルタイプ別の変更サポート
| テーブルタイプ | UPDATE | DELETE | TRUNCATE |
|------------|--------|--------|----------|
| TAG | Standard の DATA 補正: タグ選択と BASETIME の条件が必要 | `BEFORE`、タグ/軸条件、または全削除 | X |
| LOG | X | `BEFORE`、`OLDEST`、`EXCEPT`、全削除 | O |
| TRANSACTION | O | O | O |
| VOLATILE | 主キー条件 | 主キー条件または全削除 | X |
| LOOKUP | 一般条件式、PK 変更不可 | 一般条件式または全削除 | X |
LOG は入力したイベントを更新しない構造です。頻繁に変更する状態や設定は VOLATILE、LOOKUP、
TRANSACTION に保存してください。
## 変更単位と失敗処理
| 操作 | モデルで決める事項 |
|---|---|
| 現在の設定値の更新 | キー、許容値、同時更新者の処理 |
| 誤った計測値の補正 | タグ・時間範囲、補正理由、ROLLUP 再計算 |
| LOG イベントの訂正 | 原文を残して補正イベントを関連付けるか |
| 参照キーの置き換え | 参照データの切り替え順序と途中失敗の処理 |
| 期間削除 | 保持基準時刻、削除範囲、必要なバックアップ |
複数の TRANSACTION DML は明示的トランザクションにまとめられます。LOOKUP・VOLATILE の変更や
LOG・TAG 入力も同じトランザクションに参加すると考えないでください。TAG 履歴の保存後に VOLATILE
キャッシュ更新が失敗しても履歴は残る場合があり、再構築や再試行が必要です。Append の参加範囲は
API と対象タイプで異なるため、[SDK サポート範囲](/ja/dbms/development-tools-integration/sdk-support-scope/)で確認します。
複数行を変更する前に、同じ条件で件数と代表行を確認します。この事前検索は行をロックせず、
後の変更範囲を固定するものでもありません。同時入力・更新がある場合は作業時間と対象範囲も制御し、
結果の影響行数と変更後の値を確認します。
## UPDATE ポリシー
### TRANSACTION, VOLATILE, LOOKUP
- TRANSACTION は一般的なリレーショナル `UPDATE` とトランザクションをサポートします。
- VOLATILE は主キーの一致条件で対象を指定します。
- LOOKUP は一般条件式を使えますが、主キー列そのものは変更できません。
LOOKUP UPDATE には WHERE が必要です。LOOKUP・VOLATILE の主キー変更は削除と新キー入力を
別々の文で行うため、元データの保護と参照の切り替え順序を先に定めます。
両方をまとめてロールバックする必要がある場合は TRANSACTION を検討します。
LOOKUP の対応述語と式は
[LOOKUP 述語 UPDATE](/ja/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-update-syntax/)を参照してください。
### TAG data UPDATE
TAG の実際の時系列データとメタデータは、異なる構文で更新します。
| 対象 | 構文 | 主な制約 |
|------|------|-----------|
| 時系列データ | `UPDATE tag_table SET ... WHERE ...` | タグ選択と BASETIME の両条件が必要 |
| メタデータ | `UPDATE tag_table METADATA SET ...` | TAG メタデータ専用構文 |
TAG data UPDATE は Standard Edition の論理 TAG テーブルでサポートされます。タグ名、BASETIME、
メタデータ列は `SET` の対象にできません。修正範囲にマテリアライズ済みの集計があれば
`ROLLUP_REBUILD` で再構築してください。
TAG DATA の SET 右辺は既存行の列を参照できません。`SET value = value + 1` のような一括加算では
補正しません。計算済み補正値を定数またはパラメーターで渡し、必要範囲に限定します。
補正履歴が必要なら上書きだけでなく、変更前後の値と理由を別の履歴に保存します。
構文と許容式は次のリファレンスを正本とします。
- [TAG data UPDATE](/ja/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/)
- [TAG data UPDATE の WHERE/SET 制約](/ja/dbms/reference/sql/syntax/dml-syntax/tag-data-update-where-set-constraints/)
- [TAG メタデータ](/ja/dbms/tag-table-usage/tag-metadata/)
LOG は `UPDATE` をサポートしません。
## DELETE ポリシー
### TRANSACTION, VOLATILE, LOOKUP
- TRANSACTION は一般的な `WHERE` 条件で削除できます。
- VOLATILE は主キー条件で削除するか、条件なしで全行を削除できます。
- LOOKUP は一般条件式で削除するか、`WHERE` なしで全行を削除できます。
LOOKUP の対応述語は
[LOOKUP 述語 DELETE](/ja/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-delete-syntax/)を参照してください。
### LOG
LOG は任意の一般的な `WHERE` ではなく、ログ保持用の削除構文を使います。`OLDEST`、`EXCEPT`、
`BEFORE`、全削除から目的に合う形式を選びます。正確な構文と実行例は
[LOG データライフサイクル](/ja/dbms/log-table-usage/operations-lifecycle/)を参照してください。
### TAG/KV
TAG/KV は `BEFORE` で古いデータを削除するか、タグ名と軸条件で対象を選択します。
`BEFORE` の時刻は現在より過去である必要があります。構文は
[TAG データ変更](/ja/dbms/tag-table-usage/data-input-mutation/)を参照してください。
保持目的の手動削除を繰り返す場合は
[Retention Policy](/ja/dbms/operations-configuration-recovery/policy-data-retention/)を使用します。
### TAG メタデータ
`DELETE FROM table_name METADATA` で削除します。対象のタグに実データが1つでも残っていれば、
文全体が失敗します。
詳細は [TAG メタデータ](/ja/dbms/tag-table-usage/tag-metadata/)を参照してください。
## TRUNCATE ポリシー
`TRUNCATE TABLE` は LOG と TRANSACTION だけでサポートされます。スキーマとインデックス定義を
保持し、すべての行を削除します。
| 項目 | TRUNCATE | DELETE |
|------|----------|--------|
| 対象 | テーブル全体 | タイプにより全体または条件指定 |
| `WHERE` | 不可 | 対応範囲で可能 |
| TRANSACTION のロールバック | 明示的トランザクションで可能 | 明示的トランザクションで可能 |
削除前にバックアップと再入力経路を確認します。TAG は対応する `BEFORE` またはタグ/軸条件、
VOLATILE・LOOKUP の全削除は条件なしの `DELETE` を使用します。
TRANSACTION のロールバック可否を LOG の削除へ適用しないでください。確定済みの変更は後の
ROLLBACK で戻せません。また、削除と物理ディスク領域の返却は同時とは限らないため、
使用容量と対象テーブルの領域回収状態を確認します。
---
title: "4.4 アンチパターン"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/
language: ja
kind: page
---
# 4.4 アンチパターン
アンチパターンとは、特定のタイプを使うこと自体ではなく、データの意味や要件に合わない使い方です。
各例の前提が業務に当てはまるか確認し、代替案を選びます。同じスキーマでも、現在状態には適し、
履歴の蓄積には適さない場合があります。
- **[LOOKUP に無制限の履歴を蓄積](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#high-frequency-lookup)**
- **[センサー別にテーブルを作成](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#per-sensor-create)**
- **[不適切なタイプ選択](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#table-types-selection-type-wrong)**
- **[VOLATILE を永続保存に使用](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#storage-persistent-volatile)**
- **[時系列に TRANSACTION を誤用](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#time-series-storage-misuse-rdb)**
## LOOKUP に無制限の履歴を蓄積
### 問題
問題は検索頻度ではなく、増え続ける計測履歴を LOOKUP に保存する設計です。LOOKUP は全行と
インデックスをメモリに保持するため、長期履歴が増えるほどメモリ負荷も増えます。
小さな参照データをキーで繰り返し検索する用途には適しています。
### アンチパターンの例
```sql
-- 不適切: センサー計測を LOOKUP に保存
CREATE LOOKUP TABLE sensor_data_wrong (
sensor_id VARCHAR(64) PRIMARY KEY,
value DOUBLE,
ts DATETIME
);
-- sensor_id が PK のため、センサーごとに現在の1行しか保存できない
-- 履歴を追加すると同じ PK と競合する
INSERT INTO sensor_data_wrong VALUES ('TEMP-01', 25.3, NOW);
INSERT INTO sensor_data_wrong VALUES ('TEMP-01', 25.5, NOW); -- PK 重複エラー
```
### 適切なパターン
タグ別の計測履歴の収集・クエリが中心なら TAG を検討します。LOOKUP でも計測ごとに別キーを
付けられますが、全履歴がメモリに常駐するコストは残ります。最新値キャッシュは、性能上必要で
元データから復旧できる場合に VOLATILE で追加します。TAG の最新値クエリで要件を満たすなら
別キャッシュは不要です。
```sql
-- 適切: 履歴は TAG
CREATE TAG TABLE sensor_data (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
-- 最新値キャッシュは VOLATILE
CREATE VOLATILE TABLE sensor_latest (
sensor_id VARCHAR(64) PRIMARY KEY,
value DOUBLE,
updated_at DATETIME
);
```
### 結果
| | アンチパターン(LOOKUP) | 適切な設計(TAG) |
|-|-----------------|-----------------|
| 同じセンサーキーで履歴を蓄積 | X(このキーは行を識別) | O(タグ名の下に複数計測行) |
| 継続入力の経路 | 行識別子中心 | 時系列 Append API を利用可能 |
| 時間範囲クエリ | 一般条件検索 | タグ・時間軸の検索 |
## センサー別にテーブルを作成
### 問題
センサー(タグ)ごとにテーブルを作ると、センサー数に応じて DDL、権限、クエリ対象が増え、
運用コストが高くなります。
### アンチパターンの例
```sql
-- 不適切: センサーごとにテーブルを作成
CREATE TAG TABLE sensor_temp_01 (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE
);
CREATE TAG TABLE sensor_temp_02 (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE
);
CREATE TAG TABLE sensor_temp_03 (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE
);
-- ... 10,000センサーなら10,000テーブル
```
### 問題点
| 問題 | 説明 |
|------|------|
| 管理の複雑化 | テーブル数だけ DDL を管理 |
| クエリの複雑化 | センサー間集計に複数テーブルの結合が必要 |
| メタデータの増加 | システムカタログの負荷 |
| 新センサー追加 | 毎回 DDL が必要 |
### 適切なパターン
センサー名を PRIMARY KEY とする1つの TAG テーブルに、すべてのセンサーデータを保存します。
これは同じ列構造・権限・保持ポリシーを共有するセンサー群に適用します。単位、スキーマ、
アクセス権限、保持期間を個別管理するなら、テーブルを分けるのが適切な場合もあります。
センサー数そのものを分割基準にしないことが重要です。
```sql
-- 適切: すべての温度センサーを1テーブルに
CREATE TAG TABLE temperature_sensor (
name VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
-- すべてのセンサーデータを同じテーブルに入力
INSERT INTO temperature_sensor VALUES ('TEMP-01', NOW, 23.5);
INSERT INTO temperature_sensor VALUES ('TEMP-02', NOW, 24.1);
INSERT INTO temperature_sensor VALUES ('TEMP-10000', NOW, 22.9);
```
### 利点
- 新センサー追加に DDL が不要。新しいタグ名で INSERT するだけ。
- センサー間の集計が容易。
- 運用管理対象を削減。
## 不適切なタイプ選択
データの特性に合わないタイプ選択の代表例です。
### アンチパターン1: イベントログを TAG に保存
```sql
-- 不適切: イベントログを TAG に保存
CREATE TAG TABLE error_log_wrong (
name VARCHAR(256) PRIMARY KEY, -- イベント内容がタグ名になる
time DATETIME BASETIME,
level SHORT
);
-- 問題: イベントごとに一意な名前を付けるとタグ数が急増
```
**適切な設計**: LOG テーブルを使用します。
```sql
CREATE LOG TABLE error_log (
level SHORT,
msg VARCHAR(512),
src VARCHAR(128)
);
```
### アンチパターン2: センサー値を LOG に保存
LOG にセンサー値を保存すること自体は誤りではありません。問題は、タグ別の計測時刻集計が必要なのに、
実際の計測時刻を省いて受信時刻だけを残すことです。複数項目の設備イベント検索が中心なら LOG が適する場合もあります。
```sql
-- 計測時刻が必要な要件には不十分なスキーマ
CREATE LOG TABLE sensor_wrong (
sensor_id VARCHAR(64),
value DOUBLE
-- 計測時刻がなく、サーバー受信時刻だけを自動保存
);
```
**適切な設計**: TAG テーブルを使用します。
```sql
CREATE TAG TABLE sensor_measurements (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
```
### アンチパターン3: 大量の履歴を LOOKUP に保存
```sql
-- 不適切: リレーショナルトランザクションが必要な注文履歴を LOOKUP に保存
CREATE LOOKUP TABLE order_history_wrong (
order_id LONG PRIMARY KEY,
customer VARCHAR(64)
-- 全行・インデックスのメモリと明示的トランザクション要件を確認
);
```
**適切な設計**: TRANSACTION テーブルを使用します。
```sql
CREATE TRANSACTION TABLE order_history (
order_id LONG,
customer VARCHAR(64),
item_id INTEGER,
amount DOUBLE,
status VARCHAR(16)
);
-- UPDATE/DELETE/SELECT をすべてサポート
UPDATE order_history SET status = 'SHIPPED' WHERE order_id = 1001;
```
### アンチパターン4: 時系列を TRANSACTION に保存
TRANSACTION も時間列と Append API を使用できますが、TAG 専用の時間軸ストレージや ROLLUP はありません。
リレーショナルな変更より計測履歴の収集・集計が中心なら TAG を検討します。詳細は
[時系列に TRANSACTION を誤用](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#time-series-storage-misuse-rdb)を参照してください。
## VOLATILE を永続保存に使用
### 問題
永続的に保持する必要があるデータを VOLATILE に保存するパターンです。
### アンチパターンの例
```sql
-- 不適切: 重要な設定を VOLATILE に保存
CREATE VOLATILE TABLE critical_config (
key_name VARCHAR(64) PRIMARY KEY,
value VARCHAR(256)
);
INSERT INTO critical_config VALUES ('license_key', 'XXXX-XXXX-XXXX');
INSERT INTO critical_config VALUES ('max_connections', '1000');
-- 再起動ですべての設定が消失!
```
### 問題点
- サーバー停止・再起動でデータが消失します。テーブル定義は保持されます。
- プロセスが終了する障害でもメモリ内データを復旧できないため、唯一の元データを
VOLATILE に保存するとデータ損失につながります。
### 適切なパターン
永続的に必要なデータは LOOKUP または TRANSACTION に保存します。
```sql
-- 適切: 設定は LOOKUP
CREATE LOOKUP TABLE app_config (
key_name VARCHAR(64) PRIMARY KEY,
value VARCHAR(256)
);
INSERT INTO app_config VALUES ('max_connections', '1000');
-- 再起動後もデータを保持
```
### VOLATILE の適切な用途
再起動後に再生成または破棄できるデータを保存します。クエリキャッシュだけでなく、寿命が明確な
作業状態も含められます。必ず保持する業務結果をメモリだけに保存しないでください。
| 適切 | 不適切 |
|------|--------|
| センサー最新値キャッシュ | 元のトランザクションデータ |
| リアルタイム集計結果 | 重要な設定値 |
| セッションの一時状態 | 監査ログ |
| ダッシュボードキャッシュ | ユーザー情報 |
## 時系列に TRANSACTION を誤用
### 問題
センサー・IoT 計測のような継続的な時系列を TRANSACTION に保存するパターンです。リレーショナルな
更新が不要なら、TAG のタグ・時間軸と ROLLUP を利用できず、必要なクエリ・運用に合わない場合があります。
一方、計測登録と他の業務変更を1トランザクションにまとめるなら TRANSACTION を選ぶ理由があります。
### アンチパターンの例
```sql
-- 不適切: センサー時系列を TRANSACTION に保存
CREATE TRANSACTION TABLE sensor_timeseries (
sensor_id VARCHAR(64),
ts DATETIME,
value DOUBLE,
unit VARCHAR(16)
);
```
### 問題点
| 問題 | 説明 |
|------|------|
| 入力の意味が不一致 | リレーショナルトランザクション不要の値にもリレーショナル書き込みを使用 |
| 時間軸がない | TAG の BASETIME 検索構造を利用できない |
| 集計機能の違い | TAG 専用 ROLLUP を利用できない |
### 適切なパターン
センサー計測は TAG に保存します。
```sql
-- 適切: TAG を使用
CREATE TAG TABLE sensor_history (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
unit VARCHAR(16)
);
-- Append API の高速バッファで大量入力可能
-- 時間単位集計と TAG 専用最適化を利用可能
SELECT name, DATE_TRUNC('hour', time, 1) AS hour, AVG(value), MAX(value)
FROM sensor_history
WHERE time >= NOW - 86400000000000
GROUP BY name, hour;
```
### TRANSACTION が適する場合
TRANSACTION は注文、在庫、設備履歴などリレーショナルな業務データに使います。時間列があっても
UPDATE/DELETE が必要な業務履歴には TRANSACTION、変更せず蓄積する高頻度計測には TAG を選びます。
## 意味の異なる値を同じ統計で集計
スキーマが同じでも単位や行の意味が異なれば単純集計できません。累積電力量(kWh)の平均は
消費電力(kW)ではなく、区間平均の単純平均は全サンプルの平均と異なる場合があります。
NULL を0で埋めると計測失敗が正常な0になります。
型とともに単位、サンプル数、品質規則を記録します。区間統計の再集計には合計と有効件数などを
保持し、元データを削除する前に将来の分析に必要な解像度を確認します。
---
title: "4.5 モデリングパターン"
url: https://docs.machbase.com/ja/dbms/data-modeling-table-design/patterns-modeling/
language: ja
kind: page
---
# 4.5 モデリングパターン
運用環境でよく使うデータモデリングパターンを説明します。
各節の SQL は別々のモデルを示します。必要な節を選び、同名テーブルがないことを確認してから
専用の演習環境で実行します。スキーマ作成だけでは収集・集計・キャッシュ更新は自動実行されません。
入力アプリケーションやスケジューラーの処理と失敗対応も設計します。
- **[時間軸モデリング](/ja/dbms/data-modeling-table-design/patterns-modeling/#time-axis-modeling)**
- **[距離軸モデリング](/ja/dbms/data-modeling-table-design/patterns-modeling/#distance-axis-modeling)**
- **[状態・キャッシュ](/ja/dbms/data-modeling-table-design/patterns-modeling/#state-cache-status-modeling)**
- **[イベント・ログ](/ja/dbms/data-modeling-table-design/patterns-modeling/#event-log-modeling-logs)**
- **[参照・マスターデータ](/ja/dbms/data-modeling-table-design/patterns-modeling/#reference-master-modeling)**
- **[永続・一時データの組み合わせ](/ja/dbms/data-modeling-table-design/patterns-modeling/#persistent-temporary)**
- **[INSERT・UPDATE](/ja/dbms/data-modeling-table-design/patterns-modeling/#insert-update)**
- **[JOIN・メタデータ設計](/ja/dbms/data-modeling-table-design/patterns-modeling/#join-metadata-design)**
- **[複数タイプの組み合わせ](/ja/dbms/data-modeling-table-design/patterns-modeling/#table-types-patterns-combined-type)**
## 時間軸モデリング
時間を基準軸とするパターンで、センサー計測、エネルギー監視、環境データなどに適しています。
1行は1台のメーターの1回の観測です。`time` は受信時刻ではなく計測時刻とし、`kwh` が累積値か
区間使用量かを収集仕様に記録します。以下は電圧・電流も同じ観測に含む前提です。計測周期や
時刻が異なる場合は、同じ行へ無理に合わせず、別の時系列にするか欠測処理を定めます。
### 基本パターン: TAG テーブル
```sql
CREATE TAG TABLE power_meter (
meter_id VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
kwh DOUBLE,
voltage DOUBLE,
current DOUBLE
) METADATA (
location VARCHAR(64),
phase SHORT,
rating_kw DOUBLE
);
```
### 時間範囲の集計
```sql
-- 1時間ごとの平均・最大計測値(直近24時間)
SELECT meter_id,
DATE_TRUNC('hour', time, 1) AS hour,
AVG(kwh) AS avg_kwh,
MAX(kwh) AS peak_kwh
FROM power_meter
WHERE time >= NOW - 86400000000000
GROUP BY meter_id, hour
ORDER BY meter_id, hour;
```
`kwh` が累積電力量なら、上の平均はメーター指示値の平均であり、時間当たりの消費量ではありません。
区間消費量は開始・終了値の差に、初期化・交換・上限超過の処理規則を適用して求めます。
電力(kW)と電力量(kWh)も区別して列名と単位を決めます。
### 複数解像度での保存
高解像度の元データと低解像度の集計データを、別テーブルに保存します。
```sql
-- 元データ(秒単位)
CREATE TAG TABLE power_raw (
meter_id VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
kwh DOUBLE
);
-- 1分集計(VOLATILE または別 TAG にキャッシュ)
CREATE VOLATILE TABLE power_1min (
key_id VARCHAR(80) PRIMARY KEY,
meter_id VARCHAR(32),
ts DATETIME,
avg_kwh DOUBLE,
max_kwh DOUBLE
);
```
この DDL は保存領域を作るだけです。アプリケーションが `power_1min` の `key_id` にメーターと区間を
一意に識別する値を設定し、集計値を入力します。VOLATILE の結果は再起動で消えるため、長期集計の
保存先にはしません。元データ削除後も必要な統計は、永続 TAG または対応 ROLLUP に保持し、
それぞれの保持ポリシーを確認します。
### タイムゾーン処理
DATETIME は時点を表し、文字列の入出力は接続のタイムゾーンに影響されます。韓国時間で表示するには
クライアントの設定を合わせます。保存時刻に9時間を加えると、同じ時点を別タイムゾーンで表示するのではなく、
値自体を9時間後へ変えるため、表示変換と区別してください。
```sql
-- クライアントのタイムゾーンを確認し、元の時刻を取得
SELECT meter_id,
time,
kwh
FROM power_meter
WHERE meter_id = 'MTR-001'
AND time >= '2024-01-01 00:00:00';
```
入力のタイムゾーンと接続設定が異なる場合は、入力前に基準を統一します。JDBC の `TIMEZONE` 例は
[JDBC 接続](/ja/dbms/development-tools-integration/jdbc/)を参照してください。
## 距離軸モデリング
距離・位置を基準軸とするパターンで、パイプライン検査、道路センサー、レーザースキャンなどに適しています。
距離軸は時間軸の別表示ではなく、時間軸専用の ROLLUP・Retention をそのまま適用できません。
同じ管を繰り返し検査する場合、`pipe_id` だけで検査回を混在させないよう、検査 ID やテーブル分割基準を
定めます。以下は1本の管の1回の検査を前提とし、距離は m、厚さは mm です。
### 基本パターン
```sql
CREATE TAG TABLE pipeline_thickness (
pipe_id VARCHAR(32) PRIMARY KEY,
distance DOUBLE BASEDISTANCE, -- 単位: メートル
thickness DOUBLE,
temp DOUBLE
);
```
### 範囲データの検索
```sql
-- 管 ID ごとの0~50mを検索
SELECT pipe_id, distance, thickness
FROM pipeline_thickness
WHERE pipe_id = 'PIPE-A'
AND distance BETWEEN 0.0 AND 50.0
ORDER BY distance;
-- しきい値未満の箇所を検索
SELECT pipe_id, distance, thickness
FROM pipeline_thickness
WHERE pipe_id = 'PIPE-A'
AND thickness < 8.0 -- 厚さ8mm未満の箇所
ORDER BY distance;
```
### 距離に基づく集計
```sql
-- 10m区間ごとの平均厚さ
SELECT pipe_id,
FLOOR(distance / 10.0) * 10 AS segment_start,
AVG(thickness) AS avg_thickness,
MIN(thickness) AS min_thickness
FROM pipeline_thickness
WHERE pipe_id = 'PIPE-A'
GROUP BY pipe_id, FLOOR(distance / 10.0) * 10
ORDER BY segment_start;
```
### 時間と距離の複合モデル
検査時刻と位置を併せて管理する場合は、時間軸 TAG に距離列を追加します。
```sql
-- 時間軸と位置情報を保存
CREATE TAG TABLE inspection_data (
inspector VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
distance DOUBLE, -- 位置列(軸ではない)
thickness DOUBLE,
defect SHORT
);
-- 特定の日付・距離範囲を検索
SELECT inspector, time, distance, thickness
FROM inspection_data
WHERE inspector = 'INSPECTOR-01'
AND time BETWEEN '2024-01-01' AND '2024-01-02'
AND distance BETWEEN 100.0 AND 200.0
ORDER BY time;
```
## 状態・キャッシュのモデリング
デバイスやセンサーの現在状態をリアルタイムに検索するキャッシュパターンです。
### 最新状態キャッシュ
VOLATILE に各デバイスの現在状態をキャッシュします。
```sql
-- 状態キャッシュ(VOLATILE)
CREATE VOLATILE TABLE device_status (
device_id VARCHAR(64) PRIMARY KEY,
status VARCHAR(16),
value DOUBLE,
updated_at DATETIME
);
-- 状態履歴(TAG または LOG)
CREATE TAG TABLE device_status_history (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
status VARCHAR(16)
);
```
### 状態更新の流れ
以下は履歴とキャッシュを個別に更新します。2つの入力は1トランザクションではなく、別々に評価する
`NOW` も同時刻とは限りません。実際の収集では1回決めた計測時刻を両経路へ渡します。
遅れて届いた過去値が最新キャッシュを上書きしないよう、順序判定と同時更新をアプリケーションで制御します。
```sql
-- 新計測値を受信したとき:
-- 1. TAG に履歴を保存
INSERT INTO device_status_history VALUES ('DEV-01', NOW, 78.5, 'WARNING');
-- 2. VOLATILE キャッシュを更新(ON DUPLICATE KEY UPDATE)
INSERT INTO device_status VALUES ('DEV-01', 'WARNING', 78.5, NOW)
ON DUPLICATE KEY UPDATE SET status = 'WARNING', value = 78.5, updated_at = NOW;
```
### ダッシュボードのクエリ
```sql
-- 現在アラーム状態のすべてのデバイス
SELECT device_id, status, value, updated_at
FROM device_status
WHERE status IN ('ALARM', 'WARNING')
ORDER BY updated_at DESC;
-- 特定デバイスの最新状態
SELECT device_id, status, value, updated_at
FROM device_status
WHERE device_id = 'DEV-01';
```
### 状態定義の参照
状態コードの意味を LOOKUP で管理します。
```sql
CREATE LOOKUP TABLE status_definition (
code VARCHAR(16) PRIMARY KEY,
label VARCHAR(64),
color VARCHAR(16),
severity SHORT
);
INSERT INTO status_definition VALUES ('NORMAL', '正常', 'green', 0);
INSERT INTO status_definition VALUES ('WARNING', '警告', 'yellow', 1);
INSERT INTO status_definition VALUES ('ALARM', 'アラーム', 'red', 2);
-- JOIN クエリ
SELECT d.device_id, s.label, s.color, d.value
FROM device_status d
JOIN status_definition s ON d.status = s.code
ORDER BY s.severity DESC;
```
## イベント・ログのモデリング
システムイベント、アラーム、監査ログを LOG テーブルでモデル化します。
### 階層的なイベントモデル
```sql
-- アラームイベントの LOG テーブル
CREATE LOG TABLE alarm_event (
severity SHORT, -- 1=INFO, 2=WARN, 3=ERROR, 4=CRITICAL
category VARCHAR(32), -- カテゴリ
source VARCHAR(64), -- 発生元
message VARCHAR(512),
src_ip IPV4 -- 発生元 IP(ある場合)
);
-- システム監査用 LOG テーブル
CREATE LOG TABLE audit_log (
user_id VARCHAR(64),
action VARCHAR(32), -- INSERT, UPDATE, DELETE, LOGIN など
target VARCHAR(128), -- 対象テーブル/リソース
detail TEXT, -- 詳細(全文検索対象)
result VARCHAR(8) -- SUCCESS, FAILURE
);
CREATE INDEX idx_audit_detail ON audit_log(detail) INDEX_TYPE KEYWORD;
```
### アラームの集計
```sql
-- 直近1時間の重大度別アラーム数
SELECT severity, COUNT(*) AS cnt
FROM alarm_event
WHERE _arrival_time >= NOW - 3600000000000
GROUP BY severity
ORDER BY severity DESC;
-- 発生元別アラーム状況(直近24時間)
SELECT source, COUNT(*) AS total,
SUM(CASE WHEN severity = 4 THEN 1 ELSE 0 END) AS critical_cnt
FROM alarm_event
WHERE _arrival_time >= NOW - 86400000000000
GROUP BY source
ORDER BY total DESC;
```
### ログレベルのフィルタリング
```sql
-- ERROR 以上を検索(直近10分)
SELECT _arrival_time, source, message
FROM alarm_event
WHERE severity >= 3
AND _arrival_time >= NOW - 600000000000
ORDER BY _arrival_time DESC
LIMIT 100;
```
### 全文検索
```sql
-- 指定キーワードを含む監査ログを検索
SELECT _arrival_time, user_id, action, target
FROM audit_log
WHERE detail SEARCH 'password'
AND _arrival_time >= NOW - 86400000000000;
```
## 参照・マスターデータのモデリング
コード表、設備マスター、ユーザー情報などの参照データを LOOKUP でモデル化します。
履歴に識別子だけを保存すると、名前や場所の重複保存を減らせます。ただし現在のマスターの場所を
変えると、過去履歴との結合結果も新しい場所になります。発生時に所属したラインが重要なら、有効期間を
持つ変更履歴を設計するか、元の行に当時の属性を保存します。以下の階層の参照関係は外部キーで自動検証
されないため、存在しない工場・ラインコードを入力しないようアプリケーションで確認します。
### 階層的なコード体系
```sql
-- 大分類コード
CREATE LOOKUP TABLE category_main (
code VARCHAR(8) PRIMARY KEY,
label VARCHAR(64)
);
-- 中分類コード(大分類を参照)
CREATE LOOKUP TABLE category_sub (
code VARCHAR(16) PRIMARY KEY,
main_code VARCHAR(8),
label VARCHAR(64)
);
CREATE INDEX idx_sub_main ON category_sub(main_code);
```
### 設備階層マスター
```sql
-- 工場マスター
CREATE LOOKUP TABLE factory (
factory_id VARCHAR(16) PRIMARY KEY,
name VARCHAR(64),
location VARCHAR(128)
);
-- ラインマスター(工場を参照)
CREATE LOOKUP TABLE production_line (
line_id VARCHAR(16) PRIMARY KEY,
factory_id VARCHAR(16),
name VARCHAR(64)
);
-- 設備マスター(ラインを参照)
CREATE LOOKUP TABLE equipment (
equip_id VARCHAR(32) PRIMARY KEY,
line_id VARCHAR(16),
equip_name VARCHAR(128),
equip_type VARCHAR(32),
install_dt DATETIME
);
CREATE INDEX idx_equip_line ON equipment(line_id);
CREATE INDEX idx_equip_type ON equipment(equip_type);
```
### マスターの結合クエリ
計測テーブルには設備識別子を、工場・ライン・設備名などの属性は LOOKUP に1回だけ保存します。
クエリでは先に時間範囲を絞り、設備識別子で LOOKUP と結合します。構文と実行計画の確認は
[JOIN・サブクエリ](/ja/dbms/tag-table-usage/query-analysis/)を参照してください。
## 永続・一時データの組み合わせ
永続テーブル(TAG、LOG、TRANSACTION、LOOKUP)に元データを、VOLATILE にクエリ用キャッシュを
保存します。両経路を1トランザクションと考えず、キャッシュ遅延と失敗後の再構築も設計します。
### 元データと集計キャッシュ
元データは永続テーブル、集計結果は VOLATILE に保存します。
```sql
-- 元データ(TAG、永続)
CREATE TAG TABLE sensor_data (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
-- 集計キャッシュ(VOLATILE、一時)
CREATE VOLATILE TABLE sensor_recent_avg (
key_id VARCHAR(64) PRIMARY KEY,
sensor_id VARCHAR(64),
base_ts DATETIME,
avg_val DOUBLE,
max_val DOUBLE,
cnt LONG
);
```
### キャッシュ更新
キャッシュの1行は、1センサーの直近2時間の統計です。`base_ts` は集計窓の境界ではなく、含まれる
最新の計測時刻です。同じ範囲定義で計算し、同一時点の結果を比べる場合は実行ごとに基準時刻を1回
決めます。以下は未来の計測値を除外します。比較時には各 SQL の `NOW` を同じ固定基準時刻に置き換え、
下限と上限を計算します。
```sql
-- 定期集計更新(1時間ごと)
DELETE FROM sensor_recent_avg;
INSERT INTO sensor_recent_avg
SELECT name AS key_id,
name,
MAX(time) AS base_ts,
AVG(value),
MAX(value),
COUNT(*)
FROM sensor_data
WHERE time >= NOW - 3600000000000 * 2 -- 直近2時間を再計算
AND time <= NOW
GROUP BY name;
```
`INSERT ... SELECT` に `ON DUPLICATE KEY UPDATE` を付けないでください。再構築時は既存キャッシュを
削除してから再ロードします。
削除と再ロードの間は、他のクエリに空または一部だけのキャッシュが見えることがあります。
更新中の表示、失敗時の再試行、元データへのフォールバックをアプリケーションで定めます。
常に整合した完全な結果が必要なら、対応する切り替え・トランザクションモデルを検討します。
### ダッシュボードクエリの最適化
```sql
-- 保存キャッシュを検索(元データへの切り替えはアプリケーション側)
SELECT sensor_id, base_ts, avg_val, max_val
FROM sensor_recent_avg
WHERE base_ts >= NOW - 3600000000000 * 2
AND base_ts <= NOW
ORDER BY sensor_id, base_ts;
```
この条件は、最新計測時刻が直近2時間に含まれるキャッシュ行を表示します。保存済み平均を
クエリ時点で再計算するものではないため、集計の鮮度は更新周期で管理します。
### 障害復旧
再起動すると VOLATILE のデータは消失しますが、テーブル定義は残ります。元の TAG から
同じ直近2時間の統計を再計算します。以下の CREATE は、初回構築などでテーブルが存在しない場合だけ作成します。
再計算対象が元データの保持期間内に残っている必要があります。
```sql
-- キャッシュ再構築(サーバー再起動後)
CREATE VOLATILE TABLE IF NOT EXISTS sensor_recent_avg (
key_id VARCHAR(64) PRIMARY KEY,
sensor_id VARCHAR(64),
base_ts DATETIME,
avg_val DOUBLE,
max_val DOUBLE,
cnt LONG
);
INSERT INTO sensor_recent_avg
SELECT name,
name, MAX(time), AVG(value), MAX(value), COUNT(*)
FROM sensor_data
WHERE time >= NOW - 3600000000000 * 2 -- 通常更新と同じ直近2時間
AND time <= NOW
GROUP BY name;
```
復旧後、センサー別の件数・平均・最新時刻を、同じ基準時刻の元データ集計と比較します。`cnt` は
NULL 計測値も含む行数です。平均に使ったサンプル数が必要なら `COUNT(value)` を別列に保存します。
## INSERT・UPDATE パターン
モデルでは変更可能なデータを決めますが、ここでは DML 対応表を再定義しません。タイプ別の変更条件は
[データ変更ポリシー](../alter-data-mutation-policy/)、INSERT・Append・ファイル入力の選択は
[データの入力とエクスポート](/ja/dbms/development-tools-integration/data-input-load-export/)を参照してください。
## JOIN・メタデータ設計
複数タイプを組み合わせるときは次の原則を適用します。
まず結合関係を定義します。センサーコードごとにマスターが正確に1行か、工場間でコードが重複するかを
確認します。元の1行が複数の参照行に一致すると、結果行と SUM などが重複する場合があります。
名前だけでなく識別範囲と型を合わせてください。
1. 元の行数だけでなく、フィルター後の件数と実行計画で結合順序を検討します。
2. JOIN 列の型を合わせ、対応インデックスが使われるか確認します。
3. WHERE に時間範囲と業務条件を明示して結合行数を減らします。
4. TAG 属性を併せて読む目的なら、LOOKUP より METADATA が適切か検討します。
再現可能な結合例は [TAG のクエリと分析](/ja/dbms/tag-table-usage/query-analysis/)と
[LOOKUP のクエリと分析](/ja/dbms/lookup-table-usage/query-analysis/)を参照してください。
## 複数タイプの組み合わせ
運用システムで複数のテーブルタイプを組み合わせる代表的な設計です。
### 製造設備の監視システム
```
┌─────────────────────────────────────────────────────────┐
│ 設備監視システム │
├──────────────────┬──────────────────┬───────────────────┤
│ TAG │ LOG │ LOOKUP │
│ sensor_data │ alarm_event │ equipment_master │
│ 計測履歴 │ アラームイベント │ 設備参照データ │
├──────────────────┴──────────────────┴───────────────────┤
│ VOLATILE: sensor_latest(最新値キャッシュ) │
└─────────────────────────────────────────────────────────┘
```
### 物流・注文管理システム(Standard Edition)
```
┌─────────────────────────────────────────────────────────┐
│ 物流管理システム │
├──────────────────┬──────────────────┬───────────────────┤
│ TRANSACTION │ LOG │ LOOKUP │
│ orders │ delivery_log │ product_master │
│ 注文管理 │ 配送イベント │ 製品参照データ │
│ UPDATE/DELETE │ │ │
├──────────────────┴──────────────────┴───────────────────┤
│ VOLATILE: order_status_cache(現在状態キャッシュ) │
└─────────────────────────────────────────────────────────┘
```
### パターンのまとめ
| 役割 | 推奨タイプ | 理由 |
|------|---------|------|
| 高頻度の計測履歴 | TAG | Append API の高速バッファ、時系列最適化 |
| イベント・アラームログ | LOG | 追記専用、受信時刻の自動記録 |
| リレーショナル業務(UPDATE/DELETE) | TRANSACTION | SELECT/INSERT/UPDATE/DELETE 対応 |
| 参照・コード情報 | LOOKUP | PK 識別、一般条件 UPDATE/DELETE、永続性 |
| リアルタイム状態キャッシュ | VOLATILE | メモリ速度、UPSERT |
---
次に読む文書:
- [SELECT の GROUP BY と集計](/ja/dbms/reference/sql/syntax/select-syntax/)
- [運用と設定](/ja/dbms/operations-configuration-recovery/)
---
title: "5. TAGテーブルの活用"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/
language: ja
kind: section
---
# 5. TAGテーブルの活用
TAGテーブルは、繰り返し観測する対象の名前と時間軸または距離軸を使って計測履歴を保存します。
本章では、Machbase DBMS 8.7.0のTAG構造、データの入力と検索、メタデータ、補正と運用を説明します。
第3・4章で決定したデプロイ環境とデータモデルを、実際のSQLで確認します。
タグは測定対象を、DATAの1行は1回の観測を表します。METADATAはタグごとに1行の属性であり、
過去の観測ごとに保存する属性ではありません。元の測定値、現在の属性、区間集計、収集時刻を
区別すると、検索結果と訂正範囲を一貫して解釈できます。
## 本章の構成
| 節 | 内容 |
|---|---|
| [概要と使用基準](./overview-use-criteria/) | タグ識別子と観測行、時間軸・距離軸の選択 |
| [テーブル構造とスキーマ](./table-structure-schema/) | 列の順序と型、LSL/USL、BINARYとストレージ設計 |
| [作成、変更、削除](./create-alter-drop/) | 基本DDL、METADATAの拡張、オブジェクトの削除 |
| [データの入力と変更](./data-input-mutation/) | タグの自動登録、SQL・Append・ファイル入力の違い |
| [検索と分析](./query-analysis/) | 区間・最新値・STATの検索と結果の解釈 |
| [インデックスと性能](./index-performance/) | 実データによるアクセスパスの確認 |
| [運用とデータライフサイクル](./operations-lifecycle/) | 削除、保持ポリシー、重複排除の完了確認 |
| [制約、エラー、トラブルシューティング](./constraints-errors-troubleshooting/) | 正常条件と意図的に失敗させる例 |
| [活用パターンとシナリオ](./patterns-scenarios/) | 観測単位・単位系・欠損に応じたモデル |
| [TAGメタデータ](./tag-metadata/) | 登録・検索・更新・削除、JSONとARRAY |
| [TAG data UPDATEとデータ補正](./tag-data-update-correction/) | 直接訂正、NULLへの補正、監査履歴 |
| [tagmetaimportとメタデータの一括登録](./tagmetaimport/) | CSVの準備、入力先、再入力エラーの確認 |
## 実習とサポート範囲
各ページは独立した実習です。準備SQLのテーブルがすでに存在する場合は、別の業務オブジェクト
でないか確認し、無断で削除しないでください。成功例と失敗確認用の例を分けて実行し、
後片付けのSQLは実習で作成したオブジェクトだけに適用します。
TAG DATA UPDATEはStandard Edition専用です。自動重複検査期間、METADATA ALTER、LSL/USLの
詳細操作もEditionごとの範囲を確認します。SQL INSERT、Appendの処理応答、ストレージバッファの
フラッシュ、インデックス・統計処理の完了は、それぞれ意味が異なります。
ROLLUPの作成・検索・再構築の全手順は[第6章](../tag-rollup-usage/)で説明します。
本章では、TAGの訂正と削除が集計に与える影響のみ扱います。
---
title: "5.1 概要と使用基準"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/overview-use-criteria/
language: ja
kind: page
---
# 5.1 概要と使用基準
TAGは、センサーや設備など同じ対象を繰り返し観測した履歴の保存に適しています。
まず「1つのタグ」と「1行」を区別します。同じ名前で異なる時刻の行を入力でき、
タグ名が同じという理由だけで重複行が排除されることはありません。
## TAGテーブルの特性
`PRIMARY KEY`はタグ名を指定します。リレーショナルテーブルで各行を一意に識別するキーとは
役割が異なります。1つのテーブルには時間軸または距離軸を1つ指定します。
```sql
-- 時間に沿って発生した観測値を保存する時間軸TAGです。
CREATE TAG TABLE ch5_overview_time (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
-- 距離や位置の区間に基づいて観測値を保存する距離軸TAGです。
-- 距離軸TAGではROLLUPを使用できません。
CREATE TAG TABLE ch5_overview_distance (
name VARCHAR(64) PRIMARY KEY,
distance DOUBLE BASEDISTANCE,
value DOUBLE
);
```
どちらの例も、名前が1番目の列、軸が2番目の列です。時間軸は`DATETIME BASETIME`、
距離軸は`DOUBLE`、`LONG`、`ULONG`のいずれかと`BASEDISTANCE`を使用します。
`SUMMARIZED`を使用する場合は3番目の列に指定します。列の順序と指定可能な型は
[作成、変更、削除](../create-alter-drop/)、モデルごとの設計判断は
[テーブル構造とスキーマ](../table-structure-schema/)を参照してください。
`SUMMARIZED`は代表値の統計・集計に使用する列を指定する属性であり、ROLLUPオブジェクトを
自動作成するものではありません。
次の表は例のテーブルの列一覧ではなく、TAGテーブルの使用時に区別するデータの範囲です。
DATAはユーザーが入力する観測行で、METADATAとSTATはタグごとの属性・統計を確認するための
別の範囲です。
| データの範囲 | 意味 |
|---|---|
| タグ名 | センサーや繰り返し観測する対象を識別する最初の列 |
| DATA | ユーザーが入力する観測行。軸の値と複数のデータ列 |
| METADATA | タグごとの位置・単位・設定などの現在の属性。通常のDATA列とは区別 |
| STAT | `V$_STAT`で確認するタグごとの入力統計。例のテーブルの直接の列ではない |
## TAGが適している場合
- 同じスキーマで複数の対象の履歴を継続して追加します。
- 特定タグの時間・距離範囲を頻繁に検索します。
- 現在の属性を条件としてタグを選択し、その履歴を分析します。
- 時間軸TAGで繰り返し区間統計を保存・検索する必要があります。この場合、ROLLUPの設計は
[TAG ROLLUP](../../tag-rollup-usage/)で別途確認します。
単一値モデルは測定項目ごとにタグを分け、複数値モデルは同じ観測で得られた温度・圧力などを
1行にまとめます。測定時刻の異なる値を無理に同じ行に入れず、欠損・品質ポリシーを定めます。
時系列の同時刻のデータも重複収集の可能性があるため、名前・時刻・値の重複処理ポリシーを
別途確認します。
## 他のテーブルを検討する場合
| 要件 | 検討する代替案 |
|---|---|
| 観測対象よりイベント自体が重要なイベント検索 | LOG |
| 永続的なマスターデータの一般条件による検索・変更 | LOOKUP |
| 複数のDMLに対する明示的なトランザクションとリレーショナルな変更 | TRANSACTION(Standard Edition専用) |
| 元データから再構成できる共有状態キャッシュ | VOLATILE |
TAGでもJOINと制限付きの値補正を使用できます。「JOINが必要ならTAGは使えない」
「計測値は必ずTAGに保存する」といった判断は避けます。
ただし、DATAのUPDATEはStandard Edition専用です。Cluster EditionではMETADATA UPDATEのみ
使用できるため、値補正が必要な場合は再入力と再集計の手順も設計します。
## 設計手順
1. タグがセンサー・装置・検査回のどれを識別するかを決めます。
2. 測定時刻または距離・位置の意味と単位を決めます。
3. 値の型、NULLと品質表示、観測周期を決めます。
4. 観測ごとに保存する属性と現在のMETADATAを区別します。
5. 区間検索・集計・補正・保管の要件をEditionのサポート範囲と照合します。
例のテーブルの確認と削除は次のとおりです。
```sql
-- 例のテーブルのスキーマを確認します。
DESC ch5_overview_time;
DESC ch5_overview_distance;
-- 後の例と名前が重複しないように削除します。
DROP TABLE ch5_overview_distance;
DROP TABLE ch5_overview_time;
```
次は[スキーマ設計](../table-structure-schema/)と
[入力・検索の実習](../data-input-mutation/)です。
---
title: "5.2 テーブル構造とスキーマ"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/table-structure-schema/
language: ja
kind: page
---
# 5.2 テーブル構造とスキーマ
## TAGテーブルの設計
TAGテーブルの設計では、列数だけでなく、何を1つのタグとするか、どの値をどの領域に置くかを決めます。
列の位置によって決まる役割、軸列の型、指定できない型は
[作成、変更、削除](../create-alter-drop/#original-85-creating-tag-tables)を参照してください。
このページでは、その規則の範囲内で決定する項目を扱います。
このページのDDLはモデルごとの独立した例です。作成順序が必要な実習は各節で説明します。
同名の既存オブジェクトがある場合は、別名で実行します。
スキーマを決める際は、次の項目を合わせて検討します。
- [活用例](#tag-schema-use-case-summary)
- [タグ名の列](#tag-name-column-design)
- [時間軸と距離軸の選択](#time-axis-design-tag)
- [値の列の設計](#tag-table-design-design-column)
- [METADATA列の設計](#metadata-column-design-summary)
- [JSON METADATA列の設計](#json-metadata-column-design-summary)
- [バイナリデータ列の設計](#tag-table-design-design-column-binary)
- [VARCHARストレージの最適化](#tag-table-design-storage-varchar)
- [ストレージ戦略](#tag-table-design-strategy)
- [LSL・USLの設計](#tag-table-design-lsl-usl)
- [補正と重複のポリシー](#correction-duplication-policy-summary)
- [制約とサポート範囲](#tag-schema-limitations-summary)
### 活用例
TAGは、同じ構造の観測値が複数の対象から継続して蓄積される業務に適しています。センサー、設備、
移動体、検査回などの反復観測対象を先に決め、対象ごとの履歴を時間軸または距離軸で検索できるか
確認します。ここでは、対象をTAGでモデル化するか、別のテーブルタイプに分けるかを決定します。
業務モデルの例は[活用例](../patterns-scenarios/#use-cases-tag)を参照してください。
### タグ名の列
センサー別、設備別、検査回別のどの単位を1つのタグとするかを先に決めます。細かく分けるとタグ数が
増えてメタデータとインデックスの負担が大きくなり、大きくまとめると1つのタグに異なる対象の履歴が
混在します。命名規則は[VARCHARストレージの最適化](#tag-table-design-storage-varchar)でも扱います。
### 時間軸と距離軸の選択
軸は、検索条件で何を範囲指定するかに基づいて選択します。測定時刻で区間を指定する場合は時間軸、
特定経路の累積位置など距離区間で指定する場合は距離軸です。1つのTAGテーブルは両方の軸を同時に
持てないため、後から変更するにはテーブルを作り直す必要があります。
```sql
-- 測定時刻で区間を指定する時間軸TAGです。
CREATE TAG TABLE time_sensor (
name VARCHAR(40) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
```
```sql
-- 距離・位置で区間を指定する距離軸TAGです。
CREATE TAG TABLE rail_sensor (
name VARCHAR(40) PRIMARY KEY,
distance DOUBLE BASEDISTANCE,
value DOUBLE
);
```
`DURATION`、ROLLUP、時間関数はBASETIMEだけに適用されます。距離範囲の検索は通常の比較と
`BETWEEN`を使用します。実行例は[検索と分析](../query-analysis/)を参照してください。
### 値の列の設計
TAGテーブルの値の列は、タグ名と軸列を除く通常のデータ列です。
計測値、状態、品質コードなど測定行ごとに変わる値を保存します。
#### サポートされる型
以下はよく使用する型の例です。JSON、BINARY、DECIMAL、数値ARRAYを含む全サポート範囲は
[データ型リファレンス](/ja/dbms/reference/sql/types/)を参照してください。
| 型 | 説明 | 保存サイズ |
|------|------|---------|
| `DOUBLE` | 64ビット浮動小数点 | 8バイト |
| `FLOAT` | 32ビット浮動小数点 | 4バイト |
| `LONG` | 64ビット整数 | 8バイト |
| `INTEGER` (`INT`) | 32ビット整数 | 4バイト |
| `SHORT` | 16ビット整数 | 2バイト |
| `VARCHAR(n)` | 可変長文字列 | 最大nバイト |
#### 推奨する型の選択
| データ | 推奨する型 |
|--------|---------|
| 温度、湿度、圧力などのアナログ値 | `DOUBLE` |
| カウンター、状態コード | `INTEGER` |
| フラグ、二値状態 | `SHORT` |
| エネルギー、流量の累積値 | `DOUBLE`または`LONG` |
| タグの文字列値 | `VARCHAR(n)` |
#### 複数の値の列の設計
1つのテーブルに複数の計測項目を保存すると、NULL値が発生する場合があります。
計測項目が同時に収集される場合に適しています。
```sql
CREATE TAG TABLE weather_station (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
temperature DOUBLE, -- 常に収集
humidity DOUBLE, -- 常に収集
wind_speed DOUBLE, -- 任意
rainfall DOUBLE -- 任意
);
```
#### NULLを許容する設計
TAGテーブルの値の列はデフォルトでNULLを許可します。特定タグが一部の項目だけを収集する場合は、
残りの列にNULLを挿入します。
```sql
-- wind_speedとrainfallがない場合
INSERT INTO weather_station VALUES ('WS-01', NOW, 22.5, 65.0, NULL, NULL);
```
### METADATA列の設計
METADATA列はDATA行ごとに繰り返す値ではなく、タグごとの現在の属性を保存するために使用します。
設置場所、単位、装置設定、管理状態など、タグ名に付随する属性が該当します。DATAとMETADATAを
分離すると、観測履歴を維持しながらタグの現在の属性だけを検索・変更できます。ここでは各属性を
METADATAに置くかDATA列に残すかを決定します。観測ごとに値が変わる場合はDATA、タグの寿命を通して
おおむね固定ならMETADATAです。入力・検索・更新の例は
[METADATAの使用](../tag-metadata/#original-85-tag-metadata)を参照してください。
### JSON METADATA列の設計
タグ別の属性が階層構造を持つ場合や属性の集合が頻繁に変わる場合は、JSON METADATA列を検討します。
たとえば設備の場所、メーカー情報、設置オプションを1つのJSONドキュメントに保存し、必要なパスだけを
検索できます。ここではMETADATAを個別列にするか1つのJSONドキュメントにするかを決定します。
属性の集合が固定で条件検索が多い場合は個別列、タグごとに属性構成が異なる場合はJSONが適しています。
頻繁に条件として使用するパスは、インデックス設計も検討します。詳しい構文と例は
[JSON METADATA](../tag-metadata/#metadata-design-json)を参照してください。
### バイナリデータ列の設計
TAGテーブルの`BINARY(n)`は、1~32767バイトのセンサーフレームの保存に使用します。
入力リテラル、長さの制約、ドライバーの動作は[Binary列](#original-85-binary-columns)を
参照してください。大きな画像や波形は外部ストレージに置き、参照キーだけを保存する設計も検討してください。
### VARCHARストレージの最適化
`VARCHAR`は実際の最大長に合わせて宣言します。保存オプションの正確な構文は
[DDLリファレンス](/ja/dbms/reference/sql/syntax/ddl-syntax/)を参照してください。タグ名はサイト、
設備、センサーの識別子を一貫した区切り文字で組み合わせ、範囲検索できるように設計します。
### ストレージ戦略
データはタグごとに分離された列指向ストレージに保存されます。データ量と検索パターンに応じて
適切な戦略を選択します。
#### 単一テーブルと複数テーブル
##### 単一TAGテーブル(推奨)
同種のセンサーは1つのTAGテーブルにまとめて管理します。
```sql
-- 推奨: 全温度センサーを1つのテーブルにまとめる
CREATE TAG TABLE temperature_sensor (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
```
**利点**
- 管理箇所を最小化
- タグを横断する集計が容易
- 運用を簡素化
##### 複数TAGテーブル
列構成が異なる場合や保持期間・アクセス権・運用周期を分けて管理する必要がある場合は、
テーブルの分割を検討します。センサー数が増えたという理由だけでセンサー別テーブルを作成しません。
```sql
-- 温度・湿度センサー(DOUBLE値)
CREATE TAG TABLE thermo_sensor (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
temp DOUBLE,
humid DOUBLE
);
-- 振動センサー(DOUBLE + BINARY波形)
CREATE TAG TABLE vibration_sensor (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
rms DOUBLE,
waveform BINARY(4096)
);
```
#### タグ数の管理
- タグ数の増加に伴うタグインデックスとメタデータのメモリ使用量を、本番規模のデータで測定します。
- センサーの階層構造をタグ名に符号化して管理します。
- タグ名がレコードごとに一意になる設計は避けます(アンチパターン)。
#### パーティション戦略
時間軸TAGは`BASETIME`に基づいて範囲を絞って検索します。システムのストレージオブジェクトや
パーティション名に依存せず、保持期間は
[データ保持ポリシー](/ja/dbms/operations-configuration-recovery/policy-data-retention/)で管理してください。
### LSL・USLの設計
LSL(Lower Specification Limit)は下側規格限界、USL(Upper Specification Limit)は
上側規格限界です。TAGテーブルのMETADATA列にタグごとの許容範囲を設定すると、範囲外のDATA入力を
拒否できるため、タグごとに異なる入力品質基準を適用できます。
値を補正する機能ではなく、入力を拒否する機能です。範囲外の入力は収集エラーポリシーに従って
記録・再処理する必要があります。
#### 制約条件
次の制約が適用されます。
* LSL/USLをCluster全体で非サポートとは扱いません。テーブル作成時の限界定義、メタデータ値の設定、
DATA INSERT・Appendの限界検査は共通の経路です。既存METADATAに限界列をALTERで追加する
以下の実習はStandard Editionで行います。
* LSL/USLを設定するには、Tagテーブルの3番目の列__Value__に__SUMMARIZED__を指定する必要があります。
* LSLはUSL以下であり、__Value__列の入力値はLSL以上USL以下である必要があります。__(LSL <= Value <= USL)__
* LSL/USL設定前に入力されたデータは検証されません。
* LSL/USL列をNULLにすると入力データを検証しません。
* LSL/USLは個別に使用できます。上限だけを適用する場合はUSLだけを設定できます。
* USLだけを設定すると上限超過のみ、LSLだけを設定すると下限未満のみを検査します。
#### サポートされるデータ型
限界列は対象の__Value__列と同じ型である必要があります。以下では基本数値型の規格範囲設定を
説明します。SUMMARIZED自体がサポートする型にはJSONも含まれるため、SUMMARIZEDを宣言できる条件と
数値限界の設定条件は区別します。
|型|説明|範囲|有効桁数|
|----|------|-----|----|
|short|16ビット符号付き整数型|-32767 ~ 32767|-|
|ushort|16ビット符号なし整数型|0 ~ 65534|-|
|integer|32ビット符号付き整数型|-2147483647 ~ 2147483647|-|
|uinteger|32ビット符号なし整数型|0 ~ 4294967294|-|
|long|64ビット符号付き整数型|-9223372036854775807 ~ 9223372036854775807|-|
|ulong|64ビット符号なし整数型|0~18446744073709551614|-|
|float|32ビット浮動小数点データ|-|6[^1]|
|double|64ビット浮動小数点データ|-|15[^1]|
#### LSL/USLの設定と使用
次のCREATE例は異なる選択肢を示します。以降のINSERT・UPDATE実習では基本の`example`だけを使用し、
代替テーブルは別途作成します。
タグメタデータテーブルの列に`LOWER LIMIT`(LSL)または`UPPER LIMIT`(USL)キーワードを指定します。
Tagテーブルの作成時またはメタデータ列の追加時に設定できます。
##### CREATE
```sql
CREATE TAG TABLE example (
tag_id VARCHAR(50) PRIMARY KEY,
time DATETIME BASETIME,
value INTEGER SUMMARIZED)
METADATA (
lsl INTEGER LOWER LIMIT,
usl INTEGER UPPER LIMIT
);
```
2つの列を併用することも、片方だけ使用することもできます。
LSLだけを設定すると`Value >= LSL`を検査し、上限は制限しません。USL値を`NULL`にした場合と
同じ意味です。
```sql
CREATE TAG TABLE example_lower_only (
tag_id VARCHAR(50) PRIMARY KEY,
time DATETIME BASETIME,
value INTEGER SUMMARIZED)
METADATA (
lsl INTEGER LOWER LIMIT
);
```
##### ADD COLUMN
データ入力後に`ADD COLUMN`で追加する場合、デフォルト値は__NULL__です。
```sql
CREATE TAG TABLE example_alter_limits (
tag_id VARCHAR(50) PRIMARY KEY,
time DATETIME BASETIME,
value INTEGER SUMMARIZED
);
ALTER TABLE example_alter_limits METADATA ADD COLUMN (lsl INTEGER LOWER LIMIT);
ALTER TABLE example_alter_limits METADATA ADD COLUMN (usl INTEGER UPPER LIMIT);
```
[CREATE](#create)と同様、片方の属性だけを追加することもできます。
```sql
CREATE TAG TABLE example_alter_upper (
tag_id VARCHAR(50) PRIMARY KEY,
time DATETIME BASETIME,
value INTEGER SUMMARIZED
);
ALTER TABLE example_alter_upper METADATA ADD COLUMN (usl INTEGER UPPER LIMIT);
```
##### INSERT
特定のTAG IDのLSL/USL値を設定します。
```sql
INSERT INTO example metadata VALUES ('TAG_01', 100, 200);
```
設定後にタグデータを入力すると、次のように動作します。
```sql
INSERT INTO example VALUES ('TAG_01', NOW, 95); -- 失敗
```
```text
[ERR-02342: SUMMARIZED value is less than LOWER LIMIT.]
```
```sql
INSERT INTO example VALUES ('TAG_01', NOW, 100); -- 成功(境界を含む)
```
```text
1 row(s) inserted.
Elapsed time: 0.000
```
```sql
INSERT INTO example VALUES ('TAG_01', NOW, 150); -- 成功
```
```text
1 row(s) inserted.
Elapsed time: 0.000
```
```sql
INSERT INTO example VALUES ('TAG_01', NOW, 200); -- 成功(境界を含む)
```
```text
1 row(s) inserted.
Elapsed time: 0.000
```
```sql
INSERT INTO example VALUES ('TAG_01', NOW, 205); -- 失敗
```
```text
[ERR-02341: SUMMARIZED value is greater than UPPER LIMIT.]
```
Tagテーブルを検索すると、規格範囲内のデータだけが入力されたことを確認できます。
```sql
SELECT * FROM example;
```
```text
TAG_ID TIME VALUE LSL USL
------------------------------------------------------------------------------------------------------------------------------
TAG_01 2023-09-12 09:31:27 923:289:631 100 100 200
TAG_01 2023-09-12 09:31:27 929:013:232 150 100 200
TAG_01 2023-09-12 09:31:27 939:209:248 200 100 200
[3] row(s) selected.
Elapsed time: 0.001
```
##### UPDATE
LSL/USL列の値を変更します。入力済みのデータには遡及適用されない点に注意してください。
```sql
UPDATE example metadata SET lsl = 10, usl = 100 WHERE tag_id = 'TAG_01';
```
```text
1 row(s) updated.
Elapsed time: 0.001
```
```sql
SELECT tag_id, lsl, usl FROM example METADATA;
```
```text
TAG_ID LSL USL
----------------------------------------------------------------------------------------
TAG_01 10 100
[1] row(s) selected.
Elapsed time: 0.001
```
##### DELETE
LSL/USL列は`DROP COLUMN`で削除せず、値をNULLに設定して制約を解除します。
```sql
UPDATE EXAMPLE METADATA SET lsl = NULL, usl = NULL WHERE tag_id = 'TAG_01';
```
```text
1 row(s) updated.
Elapsed time: 0.001
```
```sql
SELECT tag_id, lsl, usl FROM example METADATA;
```
```text
TAG_ID LSL USL
----------------------------------------------------------------------------------------
TAG_01 NULL NULL
[1] row(s) selected.
Elapsed time: 0.001
```
#### TRACEログでLSL/USL違反を確認
- 場所: `$MACHBASE_HOME/trc/machbase.trc`
- 簡易フィルター:
```bash
grep LIMIT_DROP $MACHBASE_HOME/trc/machbase.trc | tail -n 20
```
- ログ形式: `LIMIT_DROP (TYPE=) TABLE=<テーブル名> TAG= <列名=値 ...>`
- TYPE=LOWER/UPPERで違反した限界を区別します。
- DATETIMEは`YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn`形式です。
- 実際の例:
```
[2025-11-29 13:50:34 P-151395 T-126343511537344][QP-INFO] LIMIT_DROP (TYPE=LOWER) TABLE=TAG3 TAG=tag-1 TIME=2020-01-01 00:00:00 000:000:000 VALUE=5.55
[2025-11-29 13:50:34 P-151395 T-126343511537344][QP-INFO] LIMIT_DROP (TYPE=UPPER) TABLE=TAG3 TAG=tag-1 TIME=2020-01-01 00:00:04 000:000:000 VALUE=30.55
[2025-11-29 13:50:35 P-151395 T-126344475694784][QP-INFO] LIMIT_DROP (TYPE=LOWER) TABLE=TAG3 TAG=tag-2 TIME=1998-12-24 09:00:00 000:000:000 VALUE=0
[2025-11-29 13:50:35 P-151395 T-126344475694784][QP-INFO] LIMIT_DROP (TYPE=UPPER) TABLE=TAG3 TAG=tag-2 TIME=1998-12-24 09:00:00 000:000:008 VALUE=45
```
- 活用のポイント
- TAGごとのLOWER/UPPER違反時刻と値を一覧できます。
- grepでTAG名・テーブル名を追加フィルターすると、特定対象だけを追跡できます。
- 注意: 1行は最大約4KBのため、列が多いと末尾が切れる場合があります。起動直後、メタキャッシュの
準備前はテーブル名がIDで表示される場合があります。
[^1]: [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754)
### 補正と重複のポリシー
値の補正と重複排除は列定義だけで完結しませんが、スキーマ設計時に事前に決める必要があります。
補正が必要な場合は、変更可能な値の列、元データを別列または別テーブルに保持するか、補正後のROLLUPを
どう再構築するかを決めます。DATAのUPDATEはStandard Edition専用のため、Cluster Editionでは
補正の代わりに再入力と再集計の手順を設計します。詳細は
[データ補正](../tag-data-update-correction/#design-correction-tag)を参照してください。
同じタグと同じ軸値が繰り返し入力される可能性がある場合は、重複を許可するか、収集段階で排除するか、
Machbaseの自動重複排除を使用するかを決めます。設定変更と運用検証の手順は
[自動重複排除](../operations-lifecycle/#original-85-duplication-removal)を参照してください。
### 制約とサポート範囲
TAGテーブルは反復観測の履歴に合わせた構造のため、すべてのSQL機能を一般的なリレーショナルテーブルと
同様にサポートするわけではありません。軸列、METADATA、値の補正、ROLLUP、Editionごとのサポート範囲を
設計前に確認します。ここでは設計案がサポート範囲内かを確認し、範囲外なら該当項目に戻ってスキーマを
調整します。非サポート機能と代表的なエラーは
[制約と注意事項](../constraints-errors-troubleshooting/#limitations-tag)を参照してください。
## Binary列
`BINARY(n)`はTagテーブルでセンサーフレーム用の固定長バイナリ値を保存します。
TAGで長さを省略した`BINARY`は32767バイトとして扱われます。必要なフレームサイズを明示すると、
保存・転送サイズを把握しやすくなります。TAG以外のテーブルでは長さ指定形式の`BINARY(n)`を
宣言できません。有効な長さは1~32K-1(1~32767)バイトで、インデックスは作成できません。
明示的なバイナリリテラルで`BINARY`値を入力します。
### DDLの規則
```sql
CREATE TAG TABLE t1(
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
frame BINARY(4)
);
```
- 有効な長さ: `1 <= n <= 32767`(32K-1)。
- 範囲外の場合は作成時にエラーになります(`BINARY(0)`など)。
- `DESC`とテーブルメタデータは宣言されたバイト長を表示します(16進数の幅ではありません)。
SQLの`LENGTH(binary_col)`は、短い入力値の末尾に付く0パディングを除いた表示値の長さを返します。
### サポートされる入力形式
```sql
X'hex_digits'
x'hex_digits'
B'bit_digits'
b'bit_digits'
O'octal_digits'
o'octal_digits'
```
| 形式 | 意味 | 単位 |
| --- | --- | --- |
| `X'...'`, `x'...'` | 16進数リテラル | 16進数2桁 = 1バイト |
| `B'...'`, `b'...'` | 2進数リテラル | 8ビット = 1バイト |
| `O'...'`, `o'...'` | 8進数リテラル | 8進数3桁 = 1バイト |
接頭辞は大文字・小文字のどちらも使用できます。
```sql
CREATE TAG TABLE t_bin (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value BINARY(4)
);
INSERT INTO t_bin VALUES('hex1', '2024-01-01 00:00:00', X'0A');
INSERT INTO t_bin VALUES('hex2', '2024-01-01 00:00:01', x'00010203');
INSERT INTO t_bin VALUES('bit1', '2024-01-01 00:00:02', B'00001010');
INSERT INTO t_bin VALUES('oct1', '2024-01-01 00:00:03', O'012');
```
`X'0A'`、`B'00001010'`、`O'012'`はいずれも1バイトの値`0x0A`を表します。
### バイナリリテラルの規則
#### 16進数リテラル
`X'...'`と`x'...'`には`0-9`、`A-F`、`a-f`を使用できます。
```sql
X'00'
X'0AFF'
x'abcdef'
```
16進数の文字数は必ず偶数である必要があります。2桁が1バイトに相当します。
#### 2進数リテラル
`B'...'`と`b'...'`には`0`と`1`だけを使用できます。
```sql
B'00000000' -- 0x00
B'00001010' -- 0x0A
b'11111111' -- 0xFF
```
ビット数は必ず8の倍数である必要があります。8桁が1バイトに相当します。
#### 8進数リテラル
`O'...'`と`o'...'`には`0-7`だけを使用できます。
```sql
O'000' -- 0x00
O'012' -- 0x0A
o'377' -- 0xFF
```
8進数の文字数は必ず3桁単位である必要があります。各3桁の値は`000`から`377`までの
1バイトの範囲内である必要があります。
#### 空の値
単一引用符の中を空にして、長さ0のバイナリ値を表します。
```sql
X''
B''
O''
```
### 長さの制限
`BINARY(n)`列には最大`n`バイトまで入力できます。
```sql
CREATE TAG TABLE t_limit (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value BINARY(2)
);
INSERT INTO t_limit VALUES('ok_hex', '2024-01-01 00:00:00', X'0AFF');
INSERT INTO t_limit VALUES('ok_bit', '2024-01-01 00:00:01', B'0000101011111111');
INSERT INTO t_limit VALUES('ok_oct', '2024-01-01 00:00:02', O'012377');
INSERT INTO t_limit VALUES('bad_hex', '2024-01-01 00:00:03', X'000102'); -- 失敗: 3バイト
```
入力元の種類に関係なく、最終的なバイナリ値が対象の`BINARY(n)`の長さを超えると入力は失敗します。
この規則はバイナリリテラルだけでなく、通常の文字列、従来の`'0x...'`文字列入力、他の`BINARY`列の
値を`INSERT ... SELECT`でコピーする場合にも同じように適用されます。
```sql
CREATE TAG TABLE t_src (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value BINARY(8)
);
CREATE TAG TABLE t_dst (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value BINARY(4)
);
INSERT INTO t_src VALUES('k1', '2024-01-01 00:00:00', X'0102030405060708');
INSERT INTO t_dst SELECT name, time, value FROM t_src; -- 失敗: 8バイトの値をBINARY(4)に入力
```
`CASE`、`INSERT ... SELECT`、ビューなどのSQL式で使用する場合も、最終的なバイナリ値が対象の
`BINARY(n)`の長さを超えると入力は失敗します。
### 無効な入力
次の入力は無効です。
```sql
X'0' -- 16進数の文字数が奇数
X'0G' -- Gは16進数の文字ではない
B'0101' -- ビット数が8の倍数ではない
B'00000002' -- 2は2進数の文字ではない
O'12' -- 8進数の文字数が3桁単位ではない
O'400' -- 1バイトの範囲を超過
X'0102 -- 閉じる単一引用符がない
```
不正な値または長さ超過の入力は、次のエラーで失敗します。
```text
[ERR-02233: Error occurred at column (n): (Invalid insert value.)]
```
### 従来の文字列入力との違い
互換性のため、文字列形式の`'0x...'`入力も使用できます。`'0x...'`は文字列から`BINARY`列への
変換方式であり、`X'...'`、`B'...'`、`O'...'`はSQLでバイナリ値であることを明示する
バイナリリテラルです。
通常の文字列を`BINARY(n)`列に入力することもできますが、文字列のバイト長が`n`を超えると失敗します。
新しくSQLを記述する場合は、意味が明確なバイナリリテラル形式を推奨します。
`'0b...'`、`'0o...'`、引用符のない`0x...`、`0b...`、`0o...`形式はバイナリリテラルとして
サポートされません。
### 出力とツールの補足
- machsqlは`0x`のない大文字の16進数で出力します。短い入力値の末尾に付く0パディングは
テキスト出力に表示されません。
- machloader: スキーマに`BINARY(n)`を宣言します。不正な値や長さ超過は失敗します。
- Machbase SQLCLI、ODBC、Java、C#、Node.jsドライバーは固定長バッファで送受信し、メタデータの
`LENGTH`はバイト長です。
## 例の後片付け
このページで実際に作成したテーブルのみ削除します。代替DDLを実行していない場合は、
そのテーブルのDROP文も実行しません。
```sql
DROP TABLE time_sensor;
DROP TABLE rail_sensor;
DROP TABLE weather_station;
DROP TABLE temperature_sensor;
DROP TABLE thermo_sensor;
DROP TABLE vibration_sensor;
DROP TABLE example;
DROP TABLE example_lower_only;
DROP TABLE example_alter_limits;
DROP TABLE example_alter_upper;
DROP TABLE t1;
DROP TABLE t_bin;
DROP TABLE t_limit;
DROP TABLE t_dst;
DROP TABLE t_src;
```
---
title: "5.3 作成、変更、削除"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/create-alter-drop/
language: ja
kind: page
---
# 5.3 作成、変更、削除
TAGテーブルにはタグ識別子と1つの軸列が必須です。このページでは実行可能な基本例を示し、
全オプションについてはSQLリファレンスを案内します。
## TAGテーブルの作成
TAGテーブルでは最初の2つの列の役割が固定されています。名前列と軸列は省略できず、
順序を変えたり別の位置に指定したりすると、作成に失敗します。
| 列の位置 | 用途と特性 |
| --- | --- |
| 1番目 | タグ名です。`VARCHAR`列に`PRIMARY KEY`を指定し、他の型は使用できません。センサー・設備・検査回など繰り返し観測する対象を識別します。同じタグ名で複数のDATA行を入力できるため、リレーショナルテーブルの行ごとの一意キーとは区別します。 |
| 2番目 | 観測値を時間または距離・位置で整列・検索します。時間軸は`DATETIME BASETIME`、距離軸は`DOUBLE`、`LONG`、`ULONG`のいずれかに`BASEDISTANCE`を指定します。1つのTAGテーブルに定義できるのは時間軸または距離軸のいずれか1つです。 |
| 3番目以降 | 温度、圧力、状態、品質コードなど観測ごとに変化するDATA列です。数値型、`VARCHAR`、`DATETIME`、JSON、数値ARRAY、BINARYを使用できます。複数のDATA列からタグを代表する値を1つ選ぶと、タグごとの値の統計と自動ROLLUPの基準にできます。この場合は`SUMMARIZED`を指定します。任意指定であり、3番目の列にのみ指定できます。 |
ARRAYは名前列、軸列、`SUMMARIZED`列には使用できず、それ以外のDATA列で
使用します。LOGテーブルとは異なり、TAGテーブルのDATA列では`TEXT`、`CLOB`、`BLOB`を
使用できないため、長い文字列は`VARCHAR`、バイナリデータは`BINARY`で保存します。型の表記と
値の範囲は[データ型リファレンス](/ja/dbms/reference/sql/types/)を参照してください。
タグごとに1回だけ保存する属性は、上記の列位置ではなく`METADATA`句で別途宣言します。
次の時間軸の例では`location`が該当します。
次の2つのテーブルは、このページ専用の独立した実習用です。既存オブジェクトがないことを
確認して順番に実行します。データの実際の意味に合う時間軸または距離軸を選びます。
距離軸TAGではROLLUPを使用できません。
### 時間軸TAG
```sql
CREATE TAG TABLE ch5_tag_ddl (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
) METADATA (
location VARCHAR(64)
);
```
`SUMMARIZED`を指定すると、2つの効果があります。まず、タグごとのSTATビューに`MIN_VALUE`、
`MAX_VALUE`など値自体の統計がこの列を基準として蓄積されます。`SUMMARIZED`列が
ない場合、STATには行数と軸の範囲だけが残り、値の統計は保存されません。次に、`WITH ROLLUP`に
よる自動作成とJSONドキュメント全体のROLLUPがこの列を対象とします。
一方、通常の数値ROLLUPは`CREATE ROLLUP ... ON table(column)`で列を直接指定するため、
`SUMMARIZED`がなくても作成できます。値の統計が不要でROLLUPも手動で作成する場合は指定不要です。
指定できる型はサポート対象の数値型とJSONです。ROLLUPの作成条件は
[第6章](../../tag-rollup-usage/)を参照してください。
位置・単位などタグごとに1回保存する属性は`METADATA`、測定ごとに変化する値は通常の
データ列に定義します。
### 距離軸TAG
```sql
CREATE TAG TABLE ch5_distance_ddl (
name VARCHAR(32) PRIMARY KEY,
distance DOUBLE BASEDISTANCE,
value DOUBLE
);
```
小数の距離値には`DOUBLE`、整数の軸には値の範囲に応じて`LONG`または`ULONG`を使用します。
## TAGテーブルの変更
この節のMETADATA ADD/DROP実習はStandard Editionを前提とします。
TAGデータ列の任意の変更には制限があります。スキーマを拡張する場合は、まず新しいテーブルへの
移行を検討してください。メタデータ列はサポートされる構文で追加・削除できます。
```sql
ALTER TABLE ch5_tag_ddl
METADATA ADD COLUMN (team VARCHAR(32));
ALTER TABLE ch5_tag_ddl METADATA
ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]);
ALTER TABLE ch5_tag_ddl
METADATA DROP COLUMN (team);
ALTER TABLE ch5_tag_ddl METADATA
DROP COLUMN (limits);
```
Standard EditionではTAG METADATAに固定長の数値ARRAY列を追加できます。
ALTER前から存在するメタデータ行には指定したARRAY DEFAULTが適用されます。ALTER後にTAG DATAの
入力で自動登録されるメタデータ行にはDEFAULTが再適用されず、新しいARRAY列全体がNULLになります。
TAG DATAの通常のARRAY列は`CREATE TABLE`で宣言できますが、ALTERでは追加できません。
TAG METADATA ARRAYにはインデックスが自動作成されず、明示的なインデックスもサポートされません。
詳細は[TAGメタデータ](../tag-metadata/)と
[数値ARRAY型](/ja/dbms/reference/sql/types/array/)を参照してください。
データのある運用テーブルでは、変更前に依存クエリ、SDKの列順序、再入力経路を確認します。
ALTER後は`DESC ch5_tag_ddl;`とMETADATAの検索で変更結果を確認します。
## TAGテーブルの削除
`DROP TABLE`は生データとメタデータをまとめて削除します。ROLLUPなどの依存オブジェクトがある場合は、
先に依存関係に従って削除する必要があります。TAGの`DROP TABLE ... CASCADE`は関連するROLLUPも
削除できるため、単純な後片付けの標準コマンドにはしません。
Custom ROLLUPの対象テーブルについては、別途依存関係の制約も確認します。
```sql
DROP TABLE ch5_distance_ddl;
DROP TABLE ch5_tag_ddl;
```
正確な属性、許容範囲、DDLは
[DDL構文リファレンス](/ja/dbms/reference/sql/syntax/ddl-syntax/)を参照してください。
次に読む内容:
- [TAGテーブル構造とスキーマ](../table-structure-schema/)
- [TAGデータの入力と変更](../data-input-mutation/)
- [TAGメタデータ](../tag-metadata/)
---
title: "5.4 データの入力と変更"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/data-input-mutation/
language: ja
kind: page
---
# 5.4 データの入力と変更
TAGデータはSQL `INSERT`、Append API、ファイルロードツールで入力します。SQLの例は機能確認と
少量の入力に使用し、継続的な収集にはAppend APIを優先して検討します。
## SQL INSERT
次の例では時間軸と距離軸のTAGをそれぞれ作成し、データを確認して削除します。
実習用の名前が既存テーブルと重複しないことを先に確認します。時間軸の名前はセンサーを、
距離軸の名前は1つの検査対象・検査回を識別します。
```sql
CREATE TAG TABLE ch5_input_time (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
INSERT INTO ch5_input_time
VALUES ('TEMP_001', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 25.5);
INSERT INTO ch5_input_time
VALUES ('TEMP_001', TO_DATE('2026-01-01 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 25.7);
CREATE TAG TABLE ch5_input_distance (
name VARCHAR(32) PRIMARY KEY,
distance DOUBLE BASEDISTANCE,
value DOUBLE,
quality INTEGER
);
INSERT INTO ch5_input_distance VALUES ('PIPE_A', 0.0, 10.1, 100);
INSERT INTO ch5_input_distance VALUES ('PIPE_A', 500.5, 11.2, 100);
EXEC TABLE_FLUSH(ch5_input_time);
EXEC TABLE_FLUSH(ch5_input_distance);
SELECT name, time, value FROM ch5_input_time ORDER BY time;
SELECT name, distance, value, quality
FROM ch5_input_distance
ORDER BY distance;
SELECT COUNT(*) FROM ch5_input_time;
SELECT COUNT(*) FROM ch5_input_distance;
DROP TABLE ch5_input_distance;
DROP TABLE ch5_input_time;
```
各テーブルはそれぞれ2行を返します。時間軸の値は25.5、25.7、距離軸は0.0、500.5です。
タグを事前登録していないため、最初のDATA入力でその名前が自動登録されます。
実際の発生時刻と再送の有無はアプリケーションで管理します。
`TABLE_FLUSH`は、保留中のストレージ・入力バッファを明示的にフラッシュする必要がある
検証・運用手順で使用します。トランザクションのコミットや検索時の可視性を保証する手段ではなく、
通常の収集ループで行ごとに実行しないでください。引数とエラー仕様は
[EXECプロシージャリファレンス](/ja/dbms/reference/sql/syntax/execute-procedure-syntax/#table-flush)を
参照してください。
## メタデータとともに入力
ユーザーメタデータのあるTAGでも、DATAだけを入力して新しいタグを自動登録できます。
位置・単位などを先に指定する必要がある場合は、`INSERT ... METADATA`で登録してからDATAを
入力します。データとメタデータを一緒に渡す構文もサポートされています。
通常のDATA入力のたびに登録済み属性が更新されるとは限りません。システム管理列は入力一覧に
含めないでください。
メタデータ値の登録・更新・削除は[TAGメタデータ](../tag-metadata/)を参照してください。
## 入力経路の選択
| 経路 | 適している場合 | 確認事項 |
| --- | --- | --- |
| SQL `INSERT` | 機能確認、低頻度の入力 | 文ごとの解析・往復コスト |
| SDK Append | 継続的な高スループット入力 | バッチサイズ、フラッシュ、エラー処理 |
| `csvimport` / `machloader` | クライアントファイルの一括ロード | 列順序、日付形式、badファイル |
| `LOAD DATA INFILE` | サーバーからアクセスできるファイル | サーバー上のパス・権限、エラーポリシー |
SDKごとの接続とAppendの例は[開発ツール連携](/ja/dbms/development-tools-integration/)、
ファイル形式とコマンドは
[データの入力・ロード・エクスポート](/ja/dbms/development-tools-integration/data-input-load-export/)を
参照してください。
## データの訂正
TAG data UPDATEはStandard Editionで、タグの選択条件とBASETIMEの範囲をともに指定して
実行します。タグ名、軸、メタデータ列は通常のdata UPDATEの対象にしません。
訂正後も計算済みのROLLUPは自動変更されないため、ROLLUPがある場合は対象範囲を明示的に
再構築します。手順は[ROLLUP_REBUILD](../../tag-rollup-usage/rollup-rebuild/)を参照してください。
成功応答・失敗行数と再試行ポリシーは、選択した入力APIで確認します。SQLのNULL、SDKのNULL表現、
数値の0を区別し、同じ観測を再送する場合の重複ポリシーも定めます。
数値ARRAY・スパース入力には[ARRAY Appendの例](../../development-tools-integration/data-input-load-export/array-append/)を
使用します。
詳しい手順は[TAGデータの訂正](../tag-data-update-correction/)を参照してください。
---
title: "5.5 検索と分析"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/query-analysis/
language: ja
kind: page
---
# 5.5 検索と分析
TAGテーブルから時系列データを検索する主なパターンを説明します。時間軸・距離軸の範囲検索、
複数タグの検索、統計ビューの活用を含みます。
## Tagデータの検索
### サンプルスキーマ(時間軸)
次の例はTAGテーブルに2つのタグを登録し、タグごとに10行を入力します。
`TAG_0001`は2018年1月1日から10日、`TAG_0002`は2月1日から10日のデータを使用します。
```sql
create tag table TAG (name varchar(20) primary key, time datetime basetime, value double summarized);
insert into tag metadata values ('TAG_0001');
insert into tag metadata values ('TAG_0002');
insert into tag values('TAG_0001', '2018-01-01 01:00:00 000:000:000', 1);
insert into tag values('TAG_0001', '2018-01-02 02:00:00 000:000:000', 2);
insert into tag values('TAG_0001', '2018-01-03 03:00:00 000:000:000', 3);
insert into tag values('TAG_0001', '2018-01-04 04:00:00 000:000:000', 4);
insert into tag values('TAG_0001', '2018-01-05 05:00:00 000:000:000', 5);
insert into tag values('TAG_0001', '2018-01-06 06:00:00 000:000:000', 6);
insert into tag values('TAG_0001', '2018-01-07 07:00:00 000:000:000', 7);
insert into tag values('TAG_0001', '2018-01-08 08:00:00 000:000:000', 8);
insert into tag values('TAG_0001', '2018-01-09 09:00:00 000:000:000', 9);
insert into tag values('TAG_0001', '2018-01-10 10:00:00 000:000:000', 10);
insert into tag values('TAG_0002', '2018-02-01 01:00:00 000:000:000', 11);
insert into tag values('TAG_0002', '2018-02-02 02:00:00 000:000:000', 12);
insert into tag values('TAG_0002', '2018-02-03 03:00:00 000:000:000', 13);
insert into tag values('TAG_0002', '2018-02-04 04:00:00 000:000:000', 14);
insert into tag values('TAG_0002', '2018-02-05 05:00:00 000:000:000', 15);
insert into tag values('TAG_0002', '2018-02-06 06:00:00 000:000:000', 16);
insert into tag values('TAG_0002', '2018-02-07 07:00:00 000:000:000', 17);
insert into tag values('TAG_0002', '2018-02-08 08:00:00 000:000:000', 18);
insert into tag values('TAG_0002', '2018-02-09 09:00:00 000:000:000', 19);
insert into tag values('TAG_0002', '2018-02-10 10:00:00 000:000:000', 20);
exec table_flush(tag);
```
例の最後の`TABLE_FLUSH`はストレージバッファを明示的に処理する手順です。
トランザクションのコミットや検索時の可視性を保証するコマンドとは解釈しません。詳細は
[TABLE_FLUSH](/ja/dbms/reference/sql/syntax/execute-procedure-syntax/#table-flush)を参照してください。
### 全TAGデータの抽出
```sql
select * from tag ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0001 2018-01-01 01:00:00 000:000:000 1
TAG_0001 2018-01-02 02:00:00 000:000:000 2
TAG_0001 2018-01-03 03:00:00 000:000:000 3
TAG_0001 2018-01-04 04:00:00 000:000:000 4
TAG_0001 2018-01-05 05:00:00 000:000:000 5
TAG_0001 2018-01-06 06:00:00 000:000:000 6
TAG_0001 2018-01-07 07:00:00 000:000:000 7
TAG_0001 2018-01-08 08:00:00 000:000:000 8
TAG_0001 2018-01-09 09:00:00 000:000:000 9
TAG_0001 2018-01-10 10:00:00 000:000:000 10
TAG_0002 2018-02-01 01:00:00 000:000:000 11
TAG_0002 2018-02-02 02:00:00 000:000:000 12
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
TAG_0002 2018-02-05 05:00:00 000:000:000 15
TAG_0002 2018-02-06 06:00:00 000:000:000 16
TAG_0002 2018-02-07 07:00:00 000:000:000 17
TAG_0002 2018-02-08 08:00:00 000:000:000 18
TAG_0002 2018-02-09 09:00:00 000:000:000 19
TAG_0002 2018-02-10 10:00:00 000:000:000 20
[20] row(s) selected.
```
上記は例の実行結果です。結果の順序を保証する必要がある場合は`ORDER BY name, time`を明示します。
条件のない検索の出力順序は、実行計画とスキャン方向に依存する場合があります。
### 特定のタグ名によるデータの抽出
TAG名がTAG_0002のデータを検索する例です。
```sql
select * from tag where name='TAG_0002' ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0002 2018-02-01 01:00:00 000:000:000 11
TAG_0002 2018-02-02 02:00:00 000:000:000 12
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
TAG_0002 2018-02-05 05:00:00 000:000:000 15
TAG_0002 2018-02-06 06:00:00 000:000:000 16
TAG_0002 2018-02-07 07:00:00 000:000:000 17
TAG_0002 2018-02-08 08:00:00 000:000:000 18
TAG_0002 2018-02-09 09:00:00 000:000:000 19
TAG_0002 2018-02-10 10:00:00 000:000:000 20
[10] row(s) selected.
```
### 時間範囲の検索
TAG_0002に時間範囲を指定してデータを検索する例です。
> `BETWEEN`は両方の境界を含み、`>=`と`<=`を組み合わせた条件と同じです。
> 以下の例は境界時刻にデータがないため、`>`・`<`の条件でも同じ結果を返します。
> 連続する検索区間で境界行を重複して読み取らないようにするには、
> `time >= 開始 AND time < 終了`を使用します。
```sql
select * from tag where name = 'TAG_0002' and time between to_date('2018-02-01') and to_date('2018-02-05') ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0002 2018-02-01 01:00:00 000:000:000 11
TAG_0002 2018-02-02 02:00:00 000:000:000 12
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
[4] row(s) selected.
```
```sql
select * from tag where name = 'TAG_0002' and time > to_date('2018-02-01') and time < to_date('2018-02-05') ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0002 2018-02-01 01:00:00 000:000:000 11
TAG_0002 2018-02-02 02:00:00 000:000:000 12
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
[4] row(s) selected.
```
### 距離軸のサンプルスキーマ
距離軸(`BASE DISTANCE`)のTagテーブルを使用する例です。
```sql
CREATE TAG TABLE trip_tag (
name VARCHAR(20) PRIMARY KEY,
distance_m DOUBLE BASE DISTANCE,
value DOUBLE,
quality INTEGER
);
INSERT INTO trip_tag VALUES('ODO_A', 0, 10.1, 100);
INSERT INTO trip_tag VALUES('ODO_A', 500, 11.2, 101);
INSERT INTO trip_tag VALUES('ODO_A', 1000, 12.3, 102);
INSERT INTO trip_tag VALUES('ODO_B', 1000.1, 21.5, 100);
INSERT INTO trip_tag VALUES('ODO_B', 1500, 22.1, 101);
INSERT INTO trip_tag VALUES('ODO_B', 2000, 22.9, 102);
EXEC TABLE_FLUSH(trip_tag);
```
### 距離区間の検索
```sql
SELECT name, distance_m, value, quality
FROM trip_tag
WHERE name = 'ODO_A'
AND distance_m BETWEEN 0 AND 1000
ORDER BY distance_m;
```
時間軸と同様、距離軸も軸範囲を絞り込むことが基本的な検索パターンです。
### DOUBLE距離軸の小数境界による検索
```sql
SELECT name, distance_m, value, quality
FROM trip_tag
WHERE name = 'ODO_B'
AND distance_m BETWEEN 1000.1 AND 2000
ORDER BY distance_m;
```
数値をそのまま比較するため、`1000`は除外され、`1500`と`2000`は含まれます。
### 距離軸の実行計画の確認
大規模な距離軸検索では、`EXPLAIN`で距離条件がキー範囲に含まれることを確認します。
```sql
EXPLAIN
SELECT name, distance_m, value
FROM trip_tag
WHERE name = 'ODO_B'
AND distance_m BETWEEN 1000.1 AND 2000
ORDER BY distance_m;
```
確認するポイント:
- `KEYVALUE INDEX SCAN`または同様のインデックススキャンが表示されるか
- `KEY RANGE`の下に`distance_m between ...`条件が表示されるか
### 距離バケットの集計
次の例は0以上の距離を500単位の区間に分割します。TRUNCは0方向に切り捨てるため、
負の座標の区間が必要な場合は、FLOORなど必要な境界規則を別途選択します。
```sql
SELECT TRUNC(distance_m / 500, 0) * 500 AS dist_bucket,
COUNT(*) AS sample_count,
MIN(value) AS min_v,
MAX(value) AS max_v,
AVG(value) AS avg_v
FROM trip_tag
WHERE name = 'ODO_B'
GROUP BY TRUNC(distance_m / 500, 0) * 500
ORDER BY dist_bucket;
```
たとえば`1750`は`1500`のバケットに集計されます。
### 複数タグの時間範囲検索
2つ以上のタグに同じ時間範囲を適用する例です。対象名の一覧が決まっている場合は`IN`で表します。
対象タグが多い場合の性能は、リストのサイズと時間範囲を合わせて測定します。
```sql
select * from tag where name in ('TAG_0002', 'TAG_0001') and time between to_date('2018-01-05') and to_date('2018-02-05') ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0001 2018-01-05 05:00:00 000:000:000 5
TAG_0001 2018-01-06 06:00:00 000:000:000 6
TAG_0001 2018-01-07 07:00:00 000:000:000 7
TAG_0001 2018-01-08 08:00:00 000:000:000 8
TAG_0001 2018-01-09 09:00:00 000:000:000 9
TAG_0001 2018-01-10 10:00:00 000:000:000 10
TAG_0002 2018-02-01 01:00:00 000:000:000 11
TAG_0002 2018-02-02 02:00:00 000:000:000 12
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
[10] row(s) selected.
```
### 指定値を超えるデータの検索
タグ値の条件も指定できます。TAG_0002の値から、12より大きく15より小さい値を絞り込んだ結果です。
```sql
select * from tag where name = 'TAG_0002' and value > 12 and value < 15 and time between to_date('2018-02-01') and to_date('2018-02-05') ORDER BY name, time;
```
```text
NAME TIME VALUE
--------------------------------------------------------------------------------------
TAG_0002 2018-02-03 03:00:00 000:000:000 13
TAG_0002 2018-02-04 04:00:00 000:000:000 14
[2] row(s) selected.
```
### タグ別統計ビュー`V$_STAT`
Tagテーブルを作成すると、Tag IDごとの統計情報を集計する仮想テーブルが自動作成されます。
この仮想テーブルの名前はv${tagテーブル名}_statです。
タグ名・軸に関する統計と、3番目のSUMMARIZED列の値の統計を区別します。
STATはバックグラウンドのインデックス・統計処理状態を反映するため、直前の入力の検証は
元データのSELECTと合わせて行います。すぐに統計を確認する実習では、TABLE_FLUSHの後に
INDEX_FLUSHで処理を待ちます。
BASE DISTANCEの軸別STATスキーマはMachbase 8.7.0からサポート
軸に関する列名と型はTAGテーブルの軸によって異なります。
| TAGの軸 | 最小/最大の軸値 | 最小/最大値が発生した軸値 | 最新入力行の軸値 | 軸統計の型 |
|--------|--------------|----------------------|------------------|--------------|
| `DATETIME BASE TIME` | `MIN_TIME`, `MAX_TIME` | `MIN_VALUE_TIME`, `MAX_VALUE_TIME` | `RECENT_ROW_TIME` | `DATETIME` |
| `DOUBLE/LONG/ULONG BASE DISTANCE` | `MIN_DISTANCE`, `MAX_DISTANCE` | `MIN_VALUE_DISTANCE`, `MAX_VALUE_DISTANCE` | `RECENT_ROW_DISTANCE` | 元のBASE DISTANCEの型 |
両Editionの共通列は`NAME`、`ROW_COUNT`、`MIN_VALUE`、`MAX_VALUE`です。
Cluster Editionではスキーマの先頭に`HOSTNAME VARCHAR(64)`が追加されます。
#### BASE TIME STATスキーマ
```sql
DESC v$tag_stat;
```
```text
[ COLUMN ]
----------------------------------------------------------------------------------------------------
NAME NULL? TYPE LENGTH
----------------------------------------------------------------------------------------------------
NAME varchar 100
ROW_COUNT ulong 20
MIN_TIME datetime 31
MAX_TIME datetime 31
MIN_VALUE double 17
MIN_VALUE_TIME datetime 31
MAX_VALUE double 17
MAX_VALUE_TIME datetime 31
RECENT_ROW_TIME datetime 31
```
3番目の列にSUMMARIZEDキーワードがない場合、VALUE関連情報
(MIN_VALUE、MAX_VALUE、MIN_VALUE_TIME、MAX_VALUE_TIME)は保存されません。
収集される統計情報は次のとおりです。
|列名|情報|
|--|--|
|NAME|Tag IDの名前|
|ROW_COUNT|行数|
|MIN_TIME|該当Tag IDの行で最小のbasetime列値|
|MAX_TIME|該当Tag IDの行で最大のbasetime列値|
|MIN_VALUE|該当Tag IDの行で最小のsummarized列値|
|MIN_VALUE_TIME|MIN_VALUEとともに挿入されたbasetime列値|
|MAX_VALUE|該当Tag IDの行で最大のsummarized列値|
|MAX_VALUE_TIME|MAX_VALUEとともに挿入されたbasetime列値|
|RECENT_ROW_TIME|最も最近に挿入されたbasetime列値|
次の統計実習は、前の20行の検索例とは別のテーブルを使用します。そのため、以下の2つのタグだけが
検索され、前のTAG_0001・TAG_0002が統計の期待結果に混在しません。
1. SUMMARIZED列がある場合
```sql
CREATE TAG TABLE ch5_stat_time (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED);
```
```sql
INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-12'), 10);
INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-13'), 10);
INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-14'), 20);
INSERT INTO ch5_stat_time VALUES('tag-0', TO_DATE('2021-08-11'), 5);
INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-12'), 100);
INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-11'), 200);
INSERT INTO ch5_stat_time VALUES('tag-1', TO_DATE('2022-08-10'), 50);
```
```sql
EXEC TABLE_FLUSH(ch5_stat_time);
EXEC INDEX_FLUSH(ch5_stat_time);
SELECT * FROM v$ch5_stat_time_stat ORDER BY name;
```
```text
NAME ROW_COUNT MIN_TIME MAX_TIME MIN_VALUE
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MIN_VALUE_TIME MAX_VALUE MAX_VALUE_TIME RECENT_ROW_TIME
---------------------------------------------------------------------------------------------------------------------------------
tag-0 4 2021-08-11 00:00:00 000:000:000 2021-08-14 00:00:00 000:000:000 5
2021-08-11 00:00:00 000:000:000 20 2021-08-14 00:00:00 000:000:000 2021-08-11 00:00:00 000:000:000
tag-1 3 2022-08-10 00:00:00 000:000:000 2022-08-12 00:00:00 000:000:000 50
2022-08-10 00:00:00 000:000:000 200 2022-08-11 00:00:00 000:000:000 2022-08-10 00:00:00 000:000:000
[2] row(s) selected.
```
2. SUMMARIZED列がない場合
```sql
CREATE TAG TABLE other_tag (name VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE);
```
```text
Executed successfully.
```
```sql
INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-12'), 10);
INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-13'), 10);
INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-14'), 20);
INSERT INTO other_tag VALUES('tag-0', TO_DATE('2021-08-11'), 5);
INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-12'), 100);
INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-11'), 200);
INSERT INTO other_tag VALUES('tag-1', TO_DATE('2022-08-10'), 50);
```
```sql
EXEC TABLE_FLUSH(other_tag);
EXEC INDEX_FLUSH(other_tag);
SELECT * FROM v$other_tag_stat ORDER BY name;
```
```text
NAME ROW_COUNT MIN_TIME MAX_TIME MIN_VALUE
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MIN_VALUE_TIME MAX_VALUE MAX_VALUE_TIME RECENT_ROW_TIME
---------------------------------------------------------------------------------------------------------------------------------
tag-0 4 2021-08-11 00:00:00 000:000:000 2021-08-14 00:00:00 000:000:000 NULL
NULL NULL NULL 2021-08-11 00:00:00 000:000:000
tag-1 3 2022-08-10 00:00:00 000:000:000 2022-08-12 00:00:00 000:000:000 NULL
NULL NULL NULL 2022-08-10 00:00:00 000:000:000
[2] row(s) selected.
```
#### BASE DISTANCE STATスキーマ
距離軸TAGテーブルの統計ビューは、距離値を数値型で提供します。
```sql
CREATE TAG TABLE distance_sensor (
name VARCHAR(32) PRIMARY KEY,
odometer_m DOUBLE BASE DISTANCE,
value DOUBLE SUMMARIZED
);
INSERT INTO distance_sensor VALUES('sensor', 20.5, 8);
INSERT INTO distance_sensor VALUES('sensor', 10.25, 3);
INSERT INTO distance_sensor VALUES('sensor', 30.75, 5);
EXEC TABLE_FLUSH(distance_sensor);
EXEC INDEX_FLUSH(distance_sensor);
```
Standard Editionの`DOUBLE BASE DISTANCE`テーブルのスキーマは次のとおりです。
```sql
DESC V$DISTANCE_SENSOR_STAT;
```
```text
[ COLUMN ]
----------------------------------------------------------------------------------------------------
NAME NULL? TYPE LENGTH
----------------------------------------------------------------------------------------------------
NAME varchar 100
ROW_COUNT ulong 20
MIN_DISTANCE double 17
MAX_DISTANCE double 17
MIN_VALUE double 17
MIN_VALUE_DISTANCE double 17
MAX_VALUE double 17
MAX_VALUE_DISTANCE double 17
RECENT_ROW_DISTANCE double 17
```
5つの距離軸統計列の型は、元のBASE DISTANCE列の型に従います。
| BASE DISTANCEの型 | STAT列の型 | `DESC`の長さ |
|--------------------|----------------|-------------|
| `DOUBLE` | `double` | 17 |
| `LONG` | `long` | 20 |
| `ULONG` | `ulong` | 20 |
```sql
SELECT name,
row_count,
min_distance,
max_distance,
min_value,
min_value_distance,
max_value,
max_value_distance,
recent_row_distance
FROM V$DISTANCE_SENSOR_STAT
WHERE name = 'sensor';
```
- `MIN_DISTANCE`と`MAX_DISTANCE`は、該当統計行の最小・最大距離です。
- `MIN_VALUE_DISTANCE`と`MAX_VALUE_DISTANCE`は、それぞれ最小・最大のsummarized値が発生した距離です。
- `RECENT_ROW_DISTANCE`は最大距離ではなく、最も最近に入力された行の距離です。
- `SUMMARIZED`列がない場合、`MIN_VALUE_DISTANCE`と`MAX_VALUE_DISTANCE`は`NULL`です。
##### Cluster Editionでの検索
Cluster Editionの統計ビューには`HOSTNAME`が追加され、Warehouseごとの統計行が返る場合が
あります。まずWarehouseごとの値を確認します。
```sql
SELECT hostname, name, row_count,
min_distance, max_distance,
min_value, min_value_distance,
max_value, max_value_distance,
recent_row_distance
FROM V$DISTANCE_SENSOR_STAT
ORDER BY hostname, name;
```
行数と距離の境界値は、タグ名ごとに安全に集計できます。
```sql
SELECT name,
SUM(row_count) AS row_count,
MIN(min_distance) AS min_distance,
MAX(max_distance) AS max_distance
FROM V$DISTANCE_SENSOR_STAT
GROUP BY name;
```
{{< callout type="warning" >}}
`MIN_VALUE`と`MIN_VALUE_DISTANCE`、`MAX_VALUE`と`MAX_VALUE_DISTANCE`は、同じWarehouse行の
組み合わせを維持する必要があります。2つの列を独立して`MIN`または`MAX`で集計すると、
異なるWarehouseの値が組み合わされる可能性があります。`RECENT_ROW_DISTANCE`もWarehouseごとの
最新入力距離のため、`MAX(RECENT_ROW_DISTANCE)`をクラスター全体の最新入力行と解釈しないでください。
{{< /callout >}}
##### 8.7.0との互換性
BASE DISTANCE統計ビューの従来の名前はエイリアスとして提供されません。既存テーブルも、
8.7.0サーバーが再起動すると新しいスキーマで構成されます。
| 8.7.0より前の名前 | 8.7.0の名前 |
|-----------------|------------|
| `MIN_TIME` | `MIN_DISTANCE` |
| `MAX_TIME` | `MAX_DISTANCE` |
| `MIN_VALUE_TIME` | `MIN_VALUE_DISTANCE` |
| `MAX_VALUE_TIME` | `MAX_VALUE_DISTANCE` |
| `RECENT_ROW_TIME` | `RECENT_ROW_DISTANCE` |
BASE TIME TAGテーブルは従来の`*_TIME DATETIME`スキーマを維持します。
### スキャン方向のヒント
軸方向の走査と結果のソートを区別します。軸を逆方向に検索したときの最新値は最大の軸値であり、
最後に入力した行を示すSTATのRECENT_ROW値とは異なる場合があります。
同じ軸値を持つ複数行の順序も区別する必要がある場合は、アプリケーションに追加の基準が必要です。
```sql
SELECT *
FROM tag
WHERE name = 'TAG_0001'
ORDER BY time
LIMIT 10;
SELECT /*+ SCAN_FORWARD(tag) */ name, time, value
FROM tag
WHERE name = 'TAG_0001'
LIMIT 10;
SELECT /*+ SCAN_BACKWARD(tag) */ name, time, value
FROM tag
WHERE name = 'TAG_0001'
LIMIT 10;
```
ヒントがない場合のデフォルト方向は
[TABLE_SCAN_DIRECTION](/ja/dbms/reference/configuration/configuration/)を参照してください。
## 後片付け
```sql
DROP TABLE ch5_stat_time;
DROP TABLE distance_sensor;
DROP TABLE trip_tag;
DROP TABLE other_tag;
DROP TABLE tag;
```
---
title: "5.6 インデックスと性能"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/index-performance/
language: ja
kind: page
---
# 5.6 インデックスと性能
TAGの検索では、まずタグ名と軸の範囲を絞り込むことが基本です。追加インデックスは、実際の検索条件と
実行計画を測定して選択します。
## 基本的な検索経路
TAGテーブルは`PRIMARY KEY`のタグ名と`BASETIME`または`BASEDISTANCE`の軸を基準として
検索できるように、必要な構造を自動管理します。アプリケーションは、生成されるシステムオブジェクトの
名前や保存段階に依存しないでください。
| 検索条件 | 調整方針 |
| --- | --- |
| 1つのタグの軸範囲 | タグ名と軸範囲の両方を明示 |
| 複数タグの同じ時間範囲 | まず時間範囲を制限し、対象タグ数を管理 |
| メタデータ属性 | TAG `METADATA`列として定義 |
| 繰り返す時間集計 | ROLLUPを検討 |
| 値条件が中心の検索 | 値列のセカンダリインデックスを実行計画で検証 |
タグ名や軸範囲を指定せず広範囲のデータを検索すると、読み取り範囲が大きくなります。
常に高速と考えず、実際のデータ量で`EXPLAIN`の結果と実行時間を確認してください。
## METADATA列
設置場所や装置タイプなど、タグごとに1回定義する属性は`METADATA`列として設計します。
通常のスカラーMETADATA列には検索インデックスが自動提供されます。ただしJSON列自体には
自動インデックスがないため、必要なJSONパスにインデックスを定義します。数値ARRAYメタデータ列では
自動・明示的インデックスのいずれもサポートされません。詳細は
[TAGメタデータ](../tag-metadata/)を参照してください。
時系列値や頻繁に変化する状態をMETADATAに入れると、更新経路と意味が不明確になります。
値の性質に応じてTAGデータ列、LOOKUP、VOLATILE、またはTRANSACTION(Standard Edition専用)
テーブルを検討してください。
## 値列のセカンダリインデックス
値条件を頻繁に使用する場合は、`INDEX_TYPE TAG`のセカンダリインデックスを検討できます。
追加インデックスは入力・保存コストを増やすため、作成前後の代表的なクエリを比較します。
次の例では専用の名前で値とJSONパスのインデックスを作成し、実行計画を確認して全オブジェクトを
削除します。小規模なサンプルは構文と結果の検証用であり、性能の優位性を示すものではありません。
名前が重複しない独立した環境で実行します。
```sql
CREATE TAG TABLE ch5_index_tag (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
payload JSON
) METADATA (
location VARCHAR(64)
);
INSERT INTO ch5_index_tag METADATA VALUES ('TEMP-01', 'LINE-A');
INSERT INTO ch5_index_tag METADATA VALUES ('TEMP-02', 'LINE-B');
INSERT INTO ch5_index_tag VALUES
('TEMP-01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'),
10.0, '{"state":"normal"}');
INSERT INTO ch5_index_tag VALUES
('TEMP-01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'),
90.0, '{"state":"alarm"}');
INSERT INTO ch5_index_tag VALUES
('TEMP-02', TO_DATE('2026-01-01 00:02:00', 'YYYY-MM-DD HH24:MI:SS'),
95.0, '{"state":"alarm"}');
CREATE INDEX idx_ch5_index_tag_value
ON ch5_index_tag (value) INDEX_TYPE TAG;
CREATE INDEX idx_ch5_index_tag_json
ON ch5_index_tag (payload->'$.state');
EXPLAIN SELECT name, time, value
FROM ch5_index_tag
WHERE name = 'TEMP-01'
AND time BETWEEN TO_DATE('2026-01-01', 'YYYY-MM-DD')
AND TO_DATE('2026-01-02', 'YYYY-MM-DD')
AND value > 80.0;
SELECT name, value FROM ch5_index_tag
WHERE location = 'LINE-A' AND value > 80.0
ORDER BY name, time;
SELECT name, value FROM ch5_index_tag
WHERE payload->'$.state' = 'alarm'
ORDER BY name, time;
DROP INDEX idx_ch5_index_tag_json;
DROP INDEX idx_ch5_index_tag_value;
DROP TABLE ch5_index_tag;
```
最初のSELECTはTEMP-01の90.0を1行、2番目はTEMP-01の90.0とTEMP-02の95.0を返します。
インデックス作成前後で同じ検索結果になることを確認し、本番規模のデータでは検索時間だけでなく
入力コストとインデックスサイズも比較します。
JSONパス演算子の戻り値の型と比較値の型を合わせ、対象パスが実際にインデックスを使用するか
`EXPLAIN`で確認します。
## 適用しない調整
- TAGの軸列には別途インデックスを作成しません。
- LOG用の`MINMAX_CACHE_SIZE`設定をTAGの値列に適用しません。
- 広い期間の繰り返し集計をセカンダリインデックスだけで解決しようとせず、ROLLUPを検討します。
正確なインデックス構文は[SQL構文リファレンス](/ja/dbms/reference/sql/syntax/)、
測定とチューニング手順は[クエリチューニング](/ja/dbms/performance-tuning/performance-query-tuning/)を
参照してください。
---
title: "5.7 運用とデータライフサイクル"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/operations-lifecycle/
language: ja
kind: page
---
# 5.7 運用とデータライフサイクル
TAGデータのライフサイクルは、手動削除、Retention Policy、重複入力の防止で管理します。
このページでは運用上の選択基準を説明します。全SQL構文は関連リファレンスを参照してください。
## TAGデータの削除
TAGデータはタグ識別子と軸条件を使用して削除範囲を制限します。時間軸TAGの代表的な選択肢は
次のとおりです。
| 目的 | 条件 |
| --- | --- |
| 1つのタグの全データを削除 | タグの`PRIMARY KEY`の一致 |
| 1つのタグの時間範囲を削除 | タグの一致 + BASETIME範囲 |
| 全タグの過去データを削除 | BASETIME条件または`BEFORE` |
| テーブルの全データを削除 | 条件なしのTAG `DELETE` |
次の例では専用の検証テーブルを作成し、削除範囲を確認して後片付けします。
```sql
CREATE TAG TABLE ch5_lifecycle (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
INSERT INTO ch5_lifecycle VALUES
('TAG_0001', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1.0);
INSERT INTO ch5_lifecycle VALUES
('TAG_0001', TO_DATE('2026-01-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 2.0);
INSERT INTO ch5_lifecycle VALUES
('TAG_0002', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3.0);
DELETE FROM ch5_lifecycle
WHERE name = 'TAG_0001'
AND time < TO_DATE('2026-01-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS');
SELECT name, time, value
FROM ch5_lifecycle
ORDER BY name, time;
DELETE FROM ch5_lifecycle;
SELECT COUNT(*) FROM ch5_lifecycle;
DROP TABLE ch5_lifecycle;
```
最初の削除後は、TAG_0001の2026-01-02の値2.0とTAG_0002の値3.0が残ります。
全削除後のCOUNTは0です。DATAの削除とMETADATAの削除は別の操作です。
タグの登録情報まで削除する場合は[METADATAの削除](../tag-metadata/)の条件も確認します。
削除条件の演算子とEditionごとのサポート範囲は
[TAG DELETE構文](/ja/dbms/reference/sql/syntax/dml-syntax/)を参照してください。
手動削除を定期的に繰り返す必要がある場合は、
[Retention Policy](/ja/dbms/operations-configuration-recovery/policy-data-retention/)を使用してください。
### ROLLUPデータの処理
元のTAGデータの削除と計算済みROLLUPの処理は別です。生データを訂正・削除した後に集計も変更する
必要がある場合は、対象範囲のROLLUPを再構築します。ROLLUPの削除構文を保持ポリシーのように
繰り返し実行しないでください。
- [ROLLUPの部分削除と再構築](/ja/dbms/tag-rollup-usage/rollup-rebuild/)
- [TAGデータ訂正後のROLLUP再構築](../tag-data-update-correction/)
## 自動重複排除
`TAG_DUPLICATE_CHECK_DURATION`は重複検査期間を分単位で設定します。
Standard Editionでは0~43200分を指定でき、0は無効化を表します。
Cluster Editionでは0のみ許可されるため、以下の有効化の実習はStandard Edition専用です。
サーバー時刻を基準とする検査期間内のデータで、タグ・軸・データ値が同じ行を重複と判定します。
インデックス処理と重複行の整理中に実行されるため、Appendの成功応答を「重複排除済みの行数」と
解釈しないでください。遅延到着データが検査期間外の場合は期待した重複排除が行われない場合があり、
業務キーの一意制約の代わりにはなりません。
```sql
CREATE TAG TABLE ch5_dedup (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
) TAG_DUPLICATE_CHECK_DURATION = 1440;
INSERT INTO ch5_dedup VALUES ('TAG_0001', NOW, 1.0);
INSERT INTO ch5_dedup SELECT name, time, value FROM ch5_dedup;
EXEC TABLE_FLUSH(ch5_dedup);
EXEC INDEX_FLUSH(ch5_dedup);
SELECT name, time, value
FROM ch5_dedup
WHERE name = 'TAG_0001';
ALTER TABLE ch5_dedup SET TAG_DUPLICATE_CHECK_DURATION = 60;
DROP TABLE ch5_dedup;
```
2回目の入力は最初の行のコピーなので、軸の時刻も完全に同じです。この実習は運用中の同時入力が
ないことを前提とします。ストレージバッファとインデックスの処理を待ち、1行が残ることを確認します。
通常の収集ループで行ごとに2つのフラッシュを呼び出すパターンは使用しません。
全属性と制約は現在のバージョンの
[CREATE TAG TABLE構文](/ja/dbms/reference/sql/syntax/ddl-syntax/)で確認してください。
保持ポリシーですでに削除されたデータは、重複判定の対象として残っていません。
## 運用の確認手順
1. 生データとROLLUPの保持期間をそれぞれ決めます。
2. 遅延到着データの最大遅延を測定し、重複検査期間を決めます。
3. 削除・訂正前に対象タグと時間範囲を`SELECT`で確認します。
4. 大量変更後にROLLUPと代表的な検索結果を検証します。
5. 入力量、ディスク使用量、Retentionの実行状態をまとめて監視します。
---
title: "5.8 制約、エラー、トラブルシューティング"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/constraints-errors-troubleshooting/
language: ja
kind: page
---
# 5.8 制約、エラー、トラブルシューティング
このページのUPDATE実習はStandard Editionを前提とします。まず次のテーブルを作成し、
正常なSQLと意図的に失敗するSQLを区別して実行します。失敗例を正常なスクリプトにまとめて
入れないでください。同名の既存オブジェクトは削除しません。
```sql
CREATE TAG TABLE ch5_error_time (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
status INTEGER
) METADATA (location VARCHAR(64));
INSERT INTO ch5_error_time METADATA VALUES ('sensor-01', 'zone-1');
INSERT INTO ch5_error_time METADATA VALUES ('sensor-02', 'zone-2');
INSERT INTO ch5_error_time VALUES
('sensor-01', TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 0);
INSERT INTO ch5_error_time VALUES
('sensor-02', TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 0);
CREATE TAG TABLE ch5_error_distance (
name VARCHAR(64) PRIMARY KEY,
distance DOUBLE BASEDISTANCE,
value DOUBLE SUMMARIZED
);
```
## TAG data UPDATEのWHERE条件エラー
WHERE句にはタグの選択条件とBASETIME条件の両方が必要です。
条件が曖昧な場合や許可されていない形式の場合、UPDATEは拒否されます。
{{< callout type="warning" >}}
**必須条件**
`WHERE name ...`形式のタグ選択条件と`time ...`形式のBASETIME条件をともに指定します。
条件なしの全件UPDATE、タグ条件だけのUPDATE、時間条件だけのUPDATEは許可されません。
{{< /callout >}}
### 症状
次のようなUPDATEがエラーとして拒否されます。
```sql
-- 時間条件なし
UPDATE ch5_error_time SET value = 99.9
WHERE name = 'sensor-01';
-- タグ選択条件なし
UPDATE ch5_error_time SET value = 99.9
WHERE time >= TO_DATE('2026-07-01', 'YYYY-MM-DD');
-- OR条件を使用
UPDATE ch5_error_time SET value = 99.9
WHERE name = 'sensor-01'
OR name = 'sensor-02';
```
### 原因
対象タグと時間範囲を明確に制限できない条件は拒否されます。
| 条件の形式 | サポート |
|-----------|:--------:|
| `name = 'sensor-01' AND time >= ...` | O |
| `name IN ('sensor-01', 'sensor-02') AND time BETWEEN ...` | O |
| `name LIKE 'sensor-%' AND time < ...` | O |
| `value > 10`のみ | X |
| `name = 'sensor-01'`のみ | X |
| `time >= ...`のみ | X |
| `OR`、サブクエリ、集計条件 | X |
### 解決方法
タグ選択条件と時間条件をともに明示します。
```sql
UPDATE ch5_error_time
SET value = 99.9
WHERE name = 'sensor-01'
AND time = TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS');
UPDATE ch5_error_time
SET status = 1
WHERE name IN ('sensor-01', 'sensor-02')
AND time >= TO_DATE('2026-07-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND time < TO_DATE('2026-07-02 00:00:00', 'YYYY-MM-DD HH24:MI:SS');
```
### NAMEまたはTIMEのバインドが`ERR-02190`で拒否される場合
Machbase 8.7.0以降のStandard Editionでは、次のようにNAMEとBASETIMEの条件値に
バインドパラメーターを使用できます。
```sql
UPDATE ch5_error_time
SET value = ?
WHERE name = ?
AND time = ?;
```
タグ選択条件とBASETIME条件の両方があるにもかかわらず、この文が
`ERR-02190: Invalid UPDATE/DELETE condition. Specify it as (primary key column) = (value)`で
拒否される場合は、サーバーバージョンを確認します。旧バージョンのサーバーはTAG data UPDATEの
NAME/TIMEバインドをサポートしていません。サーバーを8.7.0以降にアップグレードし、名前付きマーカーを
使用する場合は該当する名前付きAPIをサポートする8.7.0 SDKも使用します。
`?`の例はSDKで準備・バインドするSQLであり、machsqlで値を指定せずそのまま実行する文ではありません。
同じプリペアドステートメントを再利用する際は、SET、NAME、TIMEの値をすべて再バインドします。
マーカーの詳細な規則は
[TAG data UPDATEのバインド](/ja/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind)を
参照してください。
大量のUPDATEの前には、同じWHERE条件で`SELECT COUNT(*)`を実行し、変更対象の行数を確認します。
## TAG data UPDATEのSET対象列エラー
SET句は実際のデータ列だけを対象とします。PRIMARY KEY、BASETIME、メタデータ列を
SETの対象に指定するとエラーになります。
{{< callout type="warning" >}}
**SETの対象**
`value`とユーザーデータ列はUPDATEできます。`name`、`time`、METADATAブロックの列は
TAG data UPDATEのSET対象ではありません。
{{< /callout >}}
### 症状
```sql
-- エラー: PRIMARY KEY列(name)の更新を試行
UPDATE ch5_error_time
SET name = 'new-sensor'
WHERE name = 'old-sensor'
AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD');
-- エラー: BASETIME列(time)の更新を試行
UPDATE ch5_error_time
SET time = NOW
WHERE name = 'sensor-01'
AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD');
-- エラー: メタデータ列をdata UPDATEで変更
UPDATE ch5_error_time
SET location = 'zone-2'
WHERE name = 'sensor-01'
AND time >= TO_DATE('2026-07-01', 'YYYY-MM-DD');
```
### 列の種類別のUPDATE可否
| 列の種類 | 説明 | data UPDATE |
|-----------|------|:-----------:|
| PRIMARY KEY (`name`) | TAGを識別する一意キー | X |
| BASETIME (`time`) | 時系列データのタイムスタンプ | X |
| データ列(`value`、補助列) | 実際の行の値 | O |
| `SUMMARIZED`データ列 | 統計対象のデータ列 | O |
| メタデータ列 | METADATAブロックのタグ属性 | X |
### 解決方法
データ値は通常のUPDATEで変更します。
```sql
UPDATE ch5_error_time
SET value = 99.9,
status = 1
WHERE name = 'sensor-01'
AND time = TO_DATE('2026-07-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS');
```
メタデータには別の構文を使用します。
```sql
UPDATE ch5_error_time METADATA
SET location = 'zone-2'
WHERE name = 'sensor-01';
```
タグ名や時間軸を変更する必要がある場合は、新しい`name`/`time`値でデータを挿入してから、
運用ポリシーに従って既存データを削除します。
## BASE DISTANCE TAG STATの列エラー
Machbase 8.7.0はBASE DISTANCE TAGの`V$_STAT`の軸列を距離の名前と数値型で
提供します。アップグレード前のSQLが`MIN_TIME`、`MAX_TIME`、`RECENT_ROW_TIME`などを検索すると、
列が見つからないエラーになる場合があります。
### 症状
- アップグレード後、BASE DISTANCE統計ビューの従来の`*_TIME`列を検索できません。
- 旧バージョンのサーバーでは、距離値が`DATETIME`として解釈され、意味のない日付に見える場合があります。
- Cluster EditionでStandardと同じ位置ベースの結果マッピングを使用すると、先頭の`HOSTNAME`に
より後続列の対応がずれる場合があります。
### 診断
対象テーブルの軸と実際の統計ビュースキーマをともに確認します。
```sql
DESC ch5_error_distance;
DESC V$CH5_ERROR_DISTANCE_STAT;
```
BASE DISTANCEテーブルの場合、`MIN_DISTANCE`、`MAX_DISTANCE`、`MIN_VALUE_DISTANCE`、
`MAX_VALUE_DISTANCE`、`RECENT_ROW_DISTANCE`が元の距離軸の型で表示される必要があります。
Cluster Editionでは`HOSTNAME VARCHAR(64)`が先頭列に追加されます。
### 解決方法
1. SQLの従来の`*_TIME`名を、対応する`*_DISTANCE`名に変更します。
2. SDKの結果マッピングを`DATETIME`から元の`DOUBLE`、`LONG`、`ULONG`型に変更します。
3. Clusterの結果は列名で読み取るか、`HOSTNAME`を含めた位置番号を再確認します。
4. BASE TIME TAGのクエリは従来の`*_TIME DATETIME`マッピングを維持します。
全変換表とCluster集計の注意事項は
[タグ別統計ビュー](../query-analysis/#tag-stat-axis-schema)を参照してください。
## 制約と注意事項
### 機能のサポート範囲
| 機能 | 状態 |
|------|------|
| 実際の時系列データのUPDATE | Standard Editionでサポート(タグ/BASETIME条件が必要) |
| メタデータのUPDATE | サポート(`UPDATE ... METADATA`) |
| DELETE | サポート(`BEFORE`、タグ/軸条件、または全削除) |
| 複数のPRIMARY KEY | 非サポート(単一列のみ) |
| BASETIMEとBASEDISTANCEの同時使用 | 非サポート |
| TAG DATAの通常列のALTER ADD/DROP | 非サポート |
| TAG METADATA列のALTER ADD/DROP | サポート(Standard Edition) |
### タグ数の制限
- 単一のTAGテーブルに作成できるタグ数はシステム設定によって制限されます。
- タグ数が増えるとタグインデックスとメタデータのメモリ使用量も増えるため、本番規模のデータで
検索・入力性能を測定します。
- タグ名がレコードごとに一意になる設計は避けてください(アンチパターン:[センサーごとのテーブル作成](/ja/dbms/data-modeling-table-design/table-types-patterns-type-anti/#per-sensor-create)を参照)。
### 遅延到着データ
- BASETIME列には任意の過去時刻を挿入できます。
- 遅延到着データが多いワークロードでは、実際の入力レートと検索性能を別途測定します。
### Cluster Editionのサポート
TAGテーブルはCluster Editionでサポートされています。
ただしTAG data UPDATEはStandard Edition専用で、Cluster Editionではサポートされません。
### まとめ
```
TAGテーブル = センサー名 (PK) + 時間/距離軸 + 計測値
- INSERT/APPEND: O
- UPDATE: 実際のDATAはStandard Editionのタグ/BASETIME条件、METADATAは別のSQL
- DELETE: O (BEFOREまたはタグ/軸条件)
- METADATA: O (別途属性を保存、UPDATE可能)
```
---
**次に読む内容**
- [TRANSACTIONテーブルの設計](/ja/dbms/rdb-table-usage/)
## 実習の後片付け
正常な変更結果をSELECTで確認し、今回の実習テーブルのみ削除します。
```sql
SELECT name, time, value, status FROM ch5_error_time ORDER BY name, time;
DROP TABLE ch5_error_time;
DROP TABLE ch5_error_distance;
```
---
title: "5.9 活用パターンとシナリオ"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/patterns-scenarios/
language: ja
kind: page
---
# 5.9 活用パターンとシナリオ
各例は独立した実習です。テーブルの作成前に同名のオブジェクトがないことを確認します。
タグ名、1回の観測の意味、値の単位、欠損ポリシーを先に決めてからDDLを適用します。
## 活用例
### IoTセンサーデータ
工場、ビル、インフラに設置された各種センサーのデータを1つのTAGテーブルで管理します。
```sql
CREATE TAG TABLE factory_sensor (
name VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
temperature DOUBLE,
vibration DOUBLE,
current DOUBLE
);
-- 同じ設備の同じ観測による測定値を1行にまとめます。
INSERT INTO factory_sensor VALUES (
'F01/LINE-A/MOTOR-01',
NOW,
75.3, 0.15, 2.4
);
```
このモデルは、1台の装置の同時刻の観測を複数列に保存します。項目別のタグ
`.../TEMP`、`.../VIBRATION`を使用する場合は、`name, time, value`形式の単一値モデルを
検討します。項目ごとに測定時刻が異なる場合は、NULLと品質状態でその違いを表現してください。
### エネルギー監視
電力、ガス、水道メーターのデータを時間ごとに収集します。
```sql
CREATE TAG TABLE energy_meter (
meter_id VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
kwh DOUBLE,
voltage DOUBLE,
current DOUBLE
);
```
`kwh`が累積計量値の場合、AVG(kwh)は指示値の平均であり、区間使用量ではありません。
消費量は区間境界値の差にリセット・交換・欠損の処理規則を適用して計算します。
電力kWと電力量kWhを区別し、メタデータや収集仕様に単位を明記します。
### 車両・移動体の追跡
GPS座標と速度を時系列で記録します。
```sql
CREATE TAG TABLE vehicle_track (
vehicle_id VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
lat DOUBLE,
lon DOUBLE,
speed DOUBLE,
heading DOUBLE
);
```
座標系、緯度・経度、速度の単位を収集仕様に明記します。位置の欠損を数値0で置き換えると、
実際の座標と区別できません。このテーブルの作成によって空間インデックスや経路マッチングが
自動提供されるわけではありません。まず車両・時間区間で検索し、必要な分析を実行します。
### 適していない場合
- レコードごとにタグ名が変わる場合(タグ数の急増)
- タグ・時間範囲を指定せず、全データを頻繁にUPDATEする必要がある場合
- 単純なイベントログ(LOGテーブルを推奨)
## 結果の確認と後片付け
IoTの例では、次の検索で3つの測定値が同じ1行として返ることを確認します。
```sql
SELECT name, time, temperature, vibration, current FROM factory_sensor;
DROP TABLE factory_sensor;
DROP TABLE energy_meter;
DROP TABLE vehicle_track;
```
後片付けは、このページで実際に作成したテーブルだけに適用します。
---
title: "5.10 TAGメタデータ"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/tag-metadata/
language: ja
kind: page
---
# 5.10 TAGメタデータ
## Tagメタデータ
### 概要
METADATAはタグごとに1行の現在の属性です。通常のTAG検索では、同じ属性が各DATA行とともに
表示されます。現在の属性を変えると過去のDATAの検索結果にも新しい属性が表示される場合があるため、
発生時点の属性が必要な場合はDATAまたは別の属性履歴に保存します。
以下では基本メタデータ、JSONメタデータ、全体例を別々のテーブルに分けます。
タグの静的属性を保存する領域として使用し、センサー位置、装置状態、設置情報、外部識別子、
JSONドキュメント形式の属性を格納できます。
メタデータ専用SQLで次の操作を実行できます。以下の例の`TAG`はテーブル名であり、
使用時には実際のTAGテーブル名に置き換えます。
- メタデータ専用の検索
- メタデータ条件による`UPDATE` / `DELETE`
- メタデータ行の最終変更時刻の検索
- ARRAYメタデータ列のADD/DROPと既存行へのDEFAULT適用
- `JSON`型メタデータ列の宣言
- JSONパスの検索とJSONパスインデックス
- JSONドキュメントの一部だけを変更する部分更新
ユーザーは内部ストレージテーブルを直接操作せず、`TAG METADATA`構文だけを使用できます。
### メタデータ列の定義
メタデータ列は`CREATE TAG TABLE`の`METADATA (...)`句で定義します。
```sql
CREATE TAG TABLE ch5_meta (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
location VARCHAR(100),
status VARCHAR(20),
srcip IPV4
);
```
メタデータ列はタグ名ごとに1行だけ保存されます。
### ARRAYメタデータ列の追加と削除
Standard Editionでは、既存TAGテーブルのMETADATA領域に固定長の数値ARRAY列を
追加・削除できます。
```sql
INSERT INTO ch5_meta (name, time, value)
VALUES ('TEMP_OLD', TO_DATE('2026-09-05 00:00:00'), 10.0);
ALTER TABLE ch5_meta METADATA
ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]);
INSERT INTO ch5_meta (name, time, value)
VALUES ('TEMP_NEW', TO_DATE('2026-09-05 00:00:01'), 20.0);
SELECT name, limits
FROM ch5_meta METADATA
ORDER BY name;
```
ALTER前から存在する`TEMP_OLD`のメタデータ行には`[0.0000, NULL]`が補充されます。
ALTER後にTAG DATAの入力で自動登録された`TEMP_NEW`のメタデータ行にはADD COLUMNのDEFAULTが
再適用されず、`limits`全体がNULLになります。DEFAULTがない場合はALTER前の行も全体がNULLです。
追加したARRAYメタデータ列は、通常のTAG検索の明示的な射影と`SELECT *`にも含まれます。
ARRAYメタデータ列にはインデックスが自動作成されず、以下のような明示的なインデックスも
サポートされません。
```sql
-- サポートされず、エラーを返します。
CREATE INDEX idx_sensor_limits ON ch5_meta METADATA(limits);
```
列を削除する場合も`METADATA`を指定します。
```sql
ALTER TABLE ch5_meta METADATA DROP COLUMN (limits);
```
TAG DATAの通常のARRAY列は`CREATE TAG TABLE`で宣言できますが、ALTERでは追加できません。
サポートされる要素型、要素数、DEFAULTの規則は
[数値ARRAY型](/ja/dbms/reference/sql/types/array/)を参照してください。
### メタデータの入力
メタデータは`INSERT INTO ... METADATA`で入力します。
```sql
INSERT INTO ch5_meta METADATA VALUES (
'TEMP_001',
'Building-A/F1',
'READY',
'192.168.0.11'
);
```
列一覧も指定できます。
```sql
INSERT INTO ch5_meta METADATA (name, status, srcip, location)
VALUES ('TEMP_002', 'STOP', '192.168.0.12', 'Building-A/F2');
```
注意事項:
- 列一覧を省略したVALUESは、タグ名に続いてメタデータの宣言順に従います。
- 列一覧を指定した場合は、その一覧の順に値を渡します。
- 省略した入力のNULL・DEFAULT処理は、該当DDLと入力経路の規則に従います。
- 識別子はTAGのタグ名列です。この例では`name`という名前で宣言しています。
- メタデータ行の作成時に`_LAST_UPDATE_TIME`がサーバー時刻で自動記録されます。
### メタデータの検索
#### メタデータのみ検索
メタデータ専用検索は`FROM TAG METADATA`を使用します。
```sql
SELECT name, location, status, srcip
FROM ch5_meta METADATA
ORDER BY name;
```
この検索はタグ名ごとに1行を返します。
```sql
SELECT *
FROM ch5_meta METADATA
ORDER BY name;
```
`SELECT *`と`table_alias.*`は`NAME`とメタデータ列のみを返します。
`_LAST_UPDATE_TIME`などのシステム管理列は`SELECT *`の結果に表示されません。
必要な場合は列名を明示します。
#### 最終変更時刻の検索
TAGメタデータには、各メタデータ行の最終変更時刻を示すシステム管理列
`_LAST_UPDATE_TIME`があります。
`_LAST_UPDATE_TIME`はTagデータ行の最終入力時刻ではなく、Tagメタデータ行が作成された時刻、
または実際にメタデータ値が変更された時刻です。
##### 検索方法
`_LAST_UPDATE_TIME`は列名を明示して検索します。
```sql
SELECT name, _last_update_time
FROM ch5_meta METADATA;
```
他のメタデータ列とともに検索したり、条件に使用したりできます。
```sql
SELECT name, location, status, _last_update_time
FROM ch5_meta METADATA
WHERE name = 'TEMP_001';
```
`SELECT *`と`table_alias.*`の結果には`_LAST_UPDATE_TIME`は表示されません。
##### 自動記録・更新の規則
メタデータ行が新しく作成されると`_LAST_UPDATE_TIME`が自動記録されます。
```sql
INSERT INTO ch5_meta METADATA(name, location, status)
VALUES('TEMP_003', 'Building-A/F3', 'READY');
```
ユーザーメタデータ値が実際に変わると`_LAST_UPDATE_TIME`が更新されます。
```sql
UPDATE ch5_meta METADATA
SET status = 'DONE'
WHERE name = 'TEMP_003';
```
同じ値への更新やJSONの存在しないパスの削除など、保存結果が変わらない更新は実際の変更と
みなしません。この場合、`_LAST_UPDATE_TIME`は維持されます。
```sql
UPDATE ch5_meta METADATA
SET status = 'DONE'
WHERE name = 'TEMP_003';
```
JSONの存在しないパスの削除も、保存値が変わらなければno-opです。
実行例は以下のJSONテーブルを作成してから確認します。
##### 直接入力・変更の制限
`_LAST_UPDATE_TIME`はシステム管理列のため、ユーザーが直接値を入力・変更できません。
次の文は許可されません。
```sql
INSERT INTO ch5_meta METADATA(name, location, status, _last_update_time)
VALUES('TEMP_004', 'Building-A/F4', 'READY', now);
```
```sql
UPDATE ch5_meta METADATA
SET _last_update_time = now
WHERE name = 'TEMP_003';
```
また、TAGの名前列名、TAGメタデータ列名、`ALTER TABLE ... METADATA ADD COLUMN`の
対象列名に`_LAST_UPDATE_TIME`は使用できません。
`ALTER TABLE ... METADATA DROP COLUMN`で`_LAST_UPDATE_TIME`を削除することもできません。
```sql
CREATE TAG TABLE invalid_sensor (
_last_update_time VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
);
```
```sql
CREATE TAG TABLE invalid_sensor_meta (
name VARCHAR(128) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
_last_update_time DATETIME
);
```
`_LAST_UPDATE_TIME2`のように接頭辞だけが同じ名前は、別のユーザー列として使用できます。
##### 時間条件による検索と自動インデックス
`_LAST_UPDATE_TIME`には時間条件検索用のインデックスが自動提供されます。
```sql
SELECT name, location, _last_update_time
FROM ch5_meta METADATA
WHERE _last_update_time >= TO_DATE('2026-06-08 00:00:00')
ORDER BY _last_update_time;
```
そのため、ユーザーが同じ列に別のインデックスを重複作成する必要はありません。
##### machloader / tagmetaimportの使用時の注意事項
TAGメタデータのインポートでは、入力ファイルやformファイルには`NAME`とユーザーメタデータ列のみを
含めます。内部列`_ID`とシステム管理列`_LAST_UPDATE_TIME`は入力対象ではありません。
メタデータが`location`、`status`の場合、入力データは次の形式です。
```text
TEMP_001,Building-A/F1,READY
TEMP_002,Building-A/F2,STOP
```
`_LAST_UPDATE_TIME`はインポート時にサーバーが自動設定します。
通常のLOG、LOOKUP、VOLATILEテーブルでユーザーが`_LAST_UPDATE_TIME`という列を定義した場合は、
通常のユーザー列として動作します。予約された動作はTAGメタデータのシステム列だけに適用されます。
#### データとともに検索
メタデータ条件で時系列データを検索する場合は、通常の`FROM TAG`を使用します。
```sql
SELECT name, status, time, value
FROM ch5_meta
WHERE status = 'READY'
ORDER BY name, time;
```
この検索はデータ行単位で返すため、同じタグのメタデータ値が各データ行で繰り返されます。
注意事項:
- `FROM TAG METADATA`では`TIME`、`VALUE`などのデータ列は検索できません。
- `FROM TAG`はデータ検索モード、`FROM TAG METADATA`はメタデータ検索モードです。
- `TAG METADATA`では内部列`_ID`、`_RID`を使用できません。
### メタデータの更新
メタデータの更新は`UPDATE TAG METADATA`を使用します。
```sql
UPDATE ch5_meta METADATA
SET status = 'DONE',
srcip = '10.0.0.20'
WHERE name = 'TEMP_001';
```
メタデータ条件で複数タグを一度に更新することもできます。
```sql
UPDATE ch5_meta METADATA
SET status = 'DONE'
WHERE status = 'READY';
```
注意事項:
- 更新対象は`NAME`とメタデータ列です。
- `TIME`、`VALUE`などのデータ列は`UPDATE ... METADATA`で変更できません。
- 内部列は変更できません。
- 実際にメタデータ値が変わった場合だけ`_LAST_UPDATE_TIME`が更新されます。
### メタデータの削除
メタデータの削除は`DELETE FROM TAG METADATA`を使用します。
特定タグのメタデータを削除する場合は、`WHERE`句でタグ名条件を指定します。
```sql
DELETE FROM ch5_meta METADATA
WHERE name = 'TEMP_002';
```
メタデータ条件で複数タグを一度に削除することもできます。
```sql
DELETE FROM ch5_meta METADATA
WHERE status = 'STOP';
```
`WHERE`句を省略すると全メタデータが対象です。この実習には前に入力したTEMP_OLD・TEMP_NEWの
DATAが残っているため、以下の全削除は意図的に失敗します。
```sql
DELETE FROM ch5_meta METADATA;
```
注意事項:
- 削除対象のいずれかに実データ行がある場合、文全体が失敗します。
- つまり、使用中のタグのメタデータは削除できません。
- 全削除でも使用中のタグが1つでもあると、一部だけを削除せず文全体が失敗します。
使用中のタグのメタデータを削除する場合は、先にそのタグのデータ行を削除してから
メタデータ削除を再実行します。
```sql
DELETE FROM ch5_meta
WHERE name = 'TEMP_001';
DELETE FROM ch5_meta METADATA
WHERE name = 'TEMP_001';
```
### JSONメタデータ列
メタデータに`JSON`列を宣言できます。
```sql
CREATE TAG TABLE ch5_meta_json (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
info JSON
);
```
JSONメタデータの入力例:
```sql
INSERT INTO ch5_meta_json METADATA VALUES (
'SHIP_001',
'READY',
'{"name":"alpha","ship":{"status":"READY"}}'
);
```
注意事項:
- `JSON`メタデータ列には長さを指定しません。
- 無効なJSON文字列はエラーになります。
- 生のJSON列自体にはインデックスが自動作成されません。
### JSONの値が変わらない場合
```sql
SELECT name, _last_update_time FROM ch5_meta_json METADATA;
UPDATE ch5_meta_json METADATA
SET info = JSON_REMOVE(info, '$.missing')
WHERE name = 'SHIP_001';
SELECT name, _last_update_time FROM ch5_meta_json METADATA;
```
パスが存在せず保存値が変わらない場合、変更時刻も維持されます。
### JSONパスの検索
JSONメタデータは`->`演算子で検索できます。
```sql
SELECT name,
info->'$.name',
info->'$.ship.status'
FROM ch5_meta_json METADATA
WHERE info->'$.ship.status' = 'READY'
ORDER BY name;
```
データ検索でも同じ方法を使用できます。
```sql
SELECT name, time, value
FROM ch5_meta_json
WHERE info->'$.ship.status' = 'READY'
ORDER BY name, time;
```
#### パスの表記規則
検索と部分更新のパスは完全なJSONPathを使用します。
- 通常のキー: `$.name`
- ネストしたキー: `$.ship.status`
- キー名に`.`または`-`が含まれる場合は角括弧表記を使用
```sql
SELECT info->'$[''ship.owner'']'
FROM ch5_meta_json METADATA;
SELECT info->'$[''ship-owner'']'
FROM ch5_meta_json METADATA;
```
### JSONパスインデックス
#### テーブル作成時に宣言
頻繁に検索するJSONパスは、メタデータ定義時にインデックスを作成できます。
```sql
CREATE TAG TABLE ch5_meta_json_indexed (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
info JSON INDEX('name', 'ship.status')
);
```
`INDEX(...)`内の文字列は次の規則で解釈されます。
- `'name'`は`$.name`
- `'ship.status'`は`$.ship.status`
- 特殊文字のあるキーや複雑なパスは完全なJSONPathを直接使用
```sql
INFO JSON INDEX('$[''ship.owner'']')
```
#### 作成後にインデックスを追加
テーブル作成後もJSONパスインデックスを追加できます。
```sql
CREATE INDEX idx_ship_owner
ON ch5_meta_json METADATA (info->'$.owner');
```
#### インデックスの削除
インデックス名だけで削除します。
```sql
SHOW INDEX idx_ship_owner;
DROP INDEX idx_ship_owner;
```
明示的に作成したインデックスは、作成時に指定した名前で管理します。`SHOW INDEX idx_ship_owner;`は
DROP前に実行します。削除後に同名を検索すると、存在しないオブジェクトになります。
#### インデックス使用時の注意事項
現在のJSONパスインデックスは、主に文字列比較で動作します。
```sql
SELECT name
FROM ch5_meta_json METADATA
WHERE info->'$.status' = 'READY';
```
文字列リテラルとの比較はインデックスを使用できます。一方、数値リテラルとの比較は
フルスキャンになる場合があります。
例:
- `info->'$.num' = '10'`: インデックスを使用可能
- `info->'$.num' = 10`: フルスキャンの可能性あり
### JSONの部分更新
JSON関数は、指定パスを変更した新しいドキュメント値を返します。UPDATEはその結果を列に保存します。
これはパス単位の論理更新であり、保存ファイルの一部だけをその場で変更するという性能保証ではありません。
#### JSON_SET
SQLのスカラー値をJSONのスカラーとして保存します。
```sql
UPDATE ch5_meta_json METADATA
SET info = JSON_SET(info, '$.ship.status', 'DONE')
WHERE name = 'SHIP_001';
```
#### JSON_SET_JSON
入力文字列をJSONとして解釈し、オブジェクトまたは配列を保存します。
```sql
UPDATE ch5_meta_json METADATA
SET info = JSON_SET_JSON(info, '$.owner', '{"name":"machbase","team":"db"}')
WHERE name = 'SHIP_001';
```
#### JSON_REMOVE
指定したメンバーまたは下位パスを削除します。
```sql
UPDATE ch5_meta_json METADATA
SET info = JSON_REMOVE(info, '$.owner.team')
WHERE name = 'SHIP_001';
```
#### 部分更新の規則
- `JSON_SET(..., path, NULL)`はJSONの`null`を保存します。
- `JSON_SET_JSON(..., path, NULL)`の結果はSQLの`NULL`です。
- JSONドキュメント引数が`NULL`の場合、関数の結果はSQLの`NULL`です。
- パスが`NULL`または空文字列の場合はエラーになります。
- 存在しないパスへの`JSON_REMOVE`はエラーではなくno-opです。
- `JSON_REMOVE(..., '$')`は許可されません。
- 部分更新は主にオブジェクトのパスをサポートします。
- 配列要素のパス更新(例: `$.items[0]`)はサポートしません。
### 全体例
```sql
CREATE TAG TABLE ch5_meta_complete (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
)
METADATA (
status VARCHAR(20),
srcip IPV4,
info JSON INDEX('name', 'ship.status')
);
INSERT INTO ch5_meta_complete METADATA VALUES (
'SHIP_001',
'READY',
'192.168.0.11',
'{"name":"alpha","ship":{"status":"READY"}}'
);
INSERT INTO ch5_meta_complete VALUES ('SHIP_001', '2026-04-01 00:00:00', 10.5);
SELECT name, status, info
FROM ch5_meta_complete METADATA;
SELECT name, time, value
FROM ch5_meta_complete
WHERE info->'$.ship.status' = 'READY';
CREATE INDEX idx_ship_owner
ON ch5_meta_complete METADATA (info->'$.owner');
UPDATE ch5_meta_complete METADATA
SET info = JSON_SET(info, '$.ship.status', 'DONE')
WHERE name = 'SHIP_001';
DROP INDEX idx_ship_owner;
```
### まとめ
- メタデータ専用検索は`FROM TAG METADATA`
- データ検索は`FROM TAG`
- メタデータの更新・削除は`UPDATE/DELETE ... METADATA`
- ARRAYメタデータ列の変更は`ALTER TABLE ... METADATA ADD/DROP COLUMN`
- JSONメタデータは`INFO JSON`
- `_LAST_UPDATE_TIME`はメタデータ行の最終変更時刻で、明示的に検索可能
- JSONパスインデックスは`INFO JSON INDEX(...)`または`CREATE INDEX ... ON TAG METADATA (...)`
- JSONの部分更新は`JSON_SET`、`JSON_SET_JSON`、`JSON_REMOVE`
- `_LAST_UPDATE_TIME`はサーバーが自動管理し、StandardとClusterで同じ動作
## 実習の後片付け
全削除の失敗例とは異なり、DROPはテーブルとDATA・METADATAをすべて削除します。
以下の名前が今回の実習で作成したオブジェクトであることを確認して実行します。
```sql
DROP TABLE ch5_meta;
DROP TABLE ch5_meta_json;
DROP TABLE ch5_meta_json_indexed;
DROP TABLE ch5_meta_complete;
```
---
title: "5.11 TAG data UPDATEとデータ補正"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/tag-data-update-correction/
language: ja
kind: page
---
# 5.11 TAG data UPDATEとデータ補正
TAG DATAの補正には、元の値を直接変更する方法と、元の値を保持して検索時に補正値を適用する
方法があります。ROLLUPへの影響も異なります。このページのUPDATE実習は
Machbase DBMS 8.7.0 Standard Editionを前提とします。
## 値の直接訂正
タグ名とBASETIMEの条件をともに指定します。SETの右辺では既存行の列を参照できないため、
`SET value = value + 1`のような式ではなく、計算済みの値またはバインドパラメーターを渡します。
次のテーブルを、名前が重複しないことを確認して準備します。ROLLUPの訂正も確認できるように、
デフォルトのROLLUPも作成します。
```sql
CREATE TAG TABLE ch5_correction (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED,
status INTEGER
) WITH ROLLUP;
INSERT INTO ch5_correction VALUES
('TEMP-01', TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 0);
INSERT INTO ch5_correction VALUES
('TEMP-01', TO_DATE('2026-01-01 12:30:00', 'YYYY-MM-DD HH24:MI:SS'), 99.0, 0);
INSERT INTO ch5_correction VALUES
('TEMP-02', TO_DATE('2026-01-01 12:30:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 0);
```
### 範囲の確認、更新、再検索
```sql
SELECT COUNT(*), MIN(value), MAX(value)
FROM ch5_correction
WHERE name = 'TEMP-01'
AND time >= TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND time < TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS');
UPDATE ch5_correction SET value = 25.0, status = 1
WHERE name = 'TEMP-01'
AND time >= TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND time < TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS');
SELECT name, time, value, status
FROM ch5_correction ORDER BY name, time;
```
最初の検索は2件、最小値10.0、最大値99.0です。UPDATE後、TEMP-01の2行はvalue=25.0、
status=1となり、TEMP-02の20.0は維持されます。事前のCOUNTは対象をロックしないため、
同時入力がある作業では基準時刻と範囲を別途制御します。
### 複数タグとエラー処理
タグの選択には`=`、`IN`、`LIKE`を使用できます。広いパターンや長い時間範囲を変更する前に、
対象名と件数を確認し、小さな範囲に分割します。複数タグは順番に処理される場合があるため、
失敗時に文全体がアトミックに取り消されたと考えないでください。
変更済みの値と残りの対象を再検索してから再試行します。
連続する時間区間を`>= 開始 AND < 終了`で定義すると、境界行を重複処理しません。
1日全体を`23:59:59`までと指定すると、その後の小数秒データを取りこぼす可能性があります。
正確な許容条件とバインディングは[TAG UPDATE](../../reference/sql/syntax/dml-syntax/tag-data-update-syntax/)を
参照してください。
### ROLLUPの再構築
元データを変更しても計算済みのROLLUPは自動変更されません。上の実習で変更した区間を次のように
再構築し、[ROLLUPの再構築](../../tag-rollup-usage/rollup-rebuild/)の進行状況確認と
検索検証の手順に従います。
```sql
EXEC ROLLUP_REBUILD(ch5_correction, 'TEMP-01',
TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'),
TO_DATE('2026-01-01 13:00:00', 'YYYY-MM-DD HH24:MI:SS'));
```
## 元データの保持とNULLへの補正
元の値と補正値を別列に保存すると、最初の値を保持できます。補正値自体がNULLの場合もあるため、
`corrected_value IS NOT NULL`だけで補正の有無を判定せず、フラグを使用します。
```sql
CREATE TAG TABLE ch5_correction_overlay (
name VARCHAR(64) PRIMARY KEY,
time DATETIME BASETIME,
raw_value DOUBLE,
corrected_value DOUBLE,
is_corrected SHORT
);
INSERT INTO ch5_correction_overlay VALUES
('TEMP-01', TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 99.0, NULL, 0);
UPDATE ch5_correction_overlay
SET corrected_value = NULL, is_corrected = 1
WHERE name = 'TEMP-01'
AND time = TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS');
SELECT name, raw_value, is_corrected,
CASE WHEN is_corrected = 1 THEN corrected_value ELSE raw_value END AS effective_value
FROM ch5_correction_overlay;
```
raw_valueは99.0、is_correctedは1、effective_valueはNULLです。フラグが0なら元の値を
使用します。この方法は検索式で値を選択し、raw_valueは変更しません。
デフォルトROLLUPがこのCASE式を自動集計したり、raw_valueの再構築だけで補正を反映したりすると
考えず、有効値を集計する別の検索・集計モデルを定めます。
## 補正履歴と検証
複数回の変更理由と担当者を残す場合は、別途履歴を記録します。
```sql
CREATE LOG TABLE ch5_correction_log (
sensor_name VARCHAR(64),
target_time DATETIME,
old_value DOUBLE,
new_value DOUBLE,
reason VARCHAR(256),
corrected_by VARCHAR(64)
);
```
TAGの更新とLOGへの履歴記録は、1つのTRANSACTIONトランザクションにはまとめられません。
実行順序・部分失敗・再試行時に同じ作業を識別する番号をアプリケーションで設計します。
テーブルを作成するだけで監査履歴が自動記録されるわけではありません。
訂正後に元の値・有効値、影響行数、区間統計、レポートを確認します。完了後は今回の実習で作成した
オブジェクトのみ削除します。以下のCASCADEはch5_correctionのROLLUPもまとめて削除します。
```sql
DROP TABLE ch5_correction CASCADE;
DROP TABLE ch5_correction_overlay;
DROP TABLE ch5_correction_log;
```
---
title: "5.12 tagmetaimportとメタデータの一括登録"
url: https://docs.machbase.com/ja/dbms/tag-table-usage/tagmetaimport/
language: ja
kind: page
---
# 5.12 tagmetaimportとメタデータの一括登録
## tagmetaimportによるメタデータの登録
`tagmetaimport`はCSVのタグ名とユーザーメタデータをインポートするツールです。
通常のSQLの論理TAG名と`-t`の入力先を区別する必要があります。現在のラッパーは`-t`を
machloaderに渡します。以下の論理テーブル`ch5_meta_import`のメタデータ入力先は
`_CH5_META_IMPORT_META`です。`-t ch5_meta_import`が自動的にMETADATAを選択すると
考えないでください。
この名前はツールの対象指定に使用します。SQLの検索・変更には`ch5_meta_import METADATA`を
使用し、ストレージオブジェクトを直接変更する手順に拡張しないでください。デフォルトの対象に
依存せず、`-t`を明示します。
## 1. テーブルの準備
既存オブジェクトのない実習用データベースで次のSQLを実行します。
```sql
CREATE TAG TABLE ch5_meta_import (
name VARCHAR(40) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE
) METADATA (
location VARCHAR(40),
status VARCHAR(20)
);
```
## 2. CSVの準備
次の内容をクライアントの`ch5_metadata.csv`に保存します。
```csv
name,location,status
TEMP_001,Building-A/F1,READY
TEMP_002,Building-A/F2,STOP
TEMP_003,Building-B/F3,READY
```
ファイルにはタグ名に続いてMETADATAの宣言順で値を記載します。DATAのtime・valueと
システム列`_ID`・`_LAST_UPDATE_TIME`は含めません。ヘッダーがある場合は`-H`を指定します。
ヘッダーが任意の列順序を自動的に対応付けるとは考えないでください。
## 3. 入力と結果の確認
アドレス・アカウントを実際の実習用サーバーに合わせ、使用する8.7.0パッケージの`MACHBASE_HOME`と
ライブラリ環境で実行します。
```bash
tagmetaimport -s 127.0.0.1 -P 5656 -u SYS -p MANAGER \
-t _CH5_META_IMPORT_META -d ch5_metadata.csv -H \
-l ch5_import.log -b ch5_import.bad
```
初回実行の期待結果は成功3件・失敗0件です。以下のMETADATA検索は3行を返し、DATAのCOUNTは0です。
メタデータ登録と測定値の入力は異なります。
```sql
SELECT name, location, status, _last_update_time
FROM ch5_meta_import METADATA ORDER BY name;
SELECT COUNT(*) FROM ch5_meta_import;
```
## 4. 既存タグと再実行
同じファイルを再入力しても既存タグは自動更新されません。現在の経路は通常のMETADATA INSERTのため、
重複タグはエラー行として集計されます。2回目の実行の期待結果は成功0件・失敗3件で、既存属性は
維持されます。終了ステータスだけでなく、成功・失敗件数とbad/logファイルをまとめて確認します。
新しい行と不正な行が混在するファイルでも、全体が1つのトランザクションになるとは考えません。
反映済みのタグを確認し、失敗行だけを修正して再処理します。既存属性は明示的なUPDATEまたは
サポートされるUPSERTで変更します。
```sql
UPDATE ch5_meta_import METADATA SET status = 'DONE' WHERE name = 'TEMP_001';
INSERT INTO ch5_meta_import METADATA VALUES ('TEMP_002', 'Building-C/F2', 'READY')
ON DUPLICATE KEY UPDATE;
SELECT name, location, status FROM ch5_meta_import METADATA ORDER BY name;
```
TEMP_001はDONEに、TEMP_002はBuilding-C/F2・READYに変わります。
実際に値が変わると変更時刻が更新され、同じ値のno-opでは維持されます。
`tagmetaimport`に自動UPSERTオプションがあると解釈しないでください。
## 後片付けと関連ドキュメント
結果の確認後、`DROP TABLE ch5_meta_import;`で今回の実習テーブルだけを削除します。
CSV・ログ・badファイルは、再処理に不要であることを確認してから削除します。
詳細なオプションは[tagmetaimportコマンドリファレンス](../../reference/command-line-tools/tagmetaimport/)、
SQLでの登録・変更規則は[TAGメタデータ](../tag-metadata/)を参照してください。
---
title: "6. TAGテーブルのROLLUP活用"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/
language: ja
kind: section
---
# 6. TAGテーブルのROLLUP活用
ROLLUPは時間軸TAGのデータを事前集計し、検索時に統計を合算して繰り返し分析のコストを減らす機能です。
この章ではMachbase DBMS 8.7.0の基本・条件付き・拡張・JSON・Custom ROLLUPを区別し、
作成から結果検証、再構築までを説明します。
## 最初に区別する3つの間隔
| 概念 | 意味 | 例 |
|---|---|---|
| 作成時のINTERVAL | 保存する集計バケットの間隔 | 1 MIN |
| WAKEUP INTERVAL | 集計ジョブを起動する周期 | 10 SEC |
| クエリのバケット | レポートが要求する結果区間 | `rollup('min', 5, time)` |
同じバケットに複数回の部分集計が保存される場合があります。
基本ROLLUPでは公開クエリ構文が必要な統計をマージし、Customの出力先TAGではユーザーが最終再集計クエリを作成します。
元データの保持期間とROLLUPの保持・再構築ポリシーは別途定めます。
## この章の構成
| 節 | 内容 |
|---|---|
| [概要と選択基準](./overview-use-criteria/) | 基本実習と元データ・集計の比較 |
| [対象TAGの設計](./target-tag-table-design/) | ON/FROM、階層の制約、容量見積もり |
| [作成と削除](./create-delete-rollup/) | CREATE、WITH ROLLUP、IF NOT EXISTSと依存関係 |
| [クエリ構文](./query-syntax-rollup/) | 候補選択、時間単位、origin |
| [条件付きROLLUP](./conditional-rollup/) | 元データのフィルターと明示的な候補選択 |
| [Custom ROLLUP](./custom-rollup/) | 増分結果の再集計とOHLCV階層 |
| [拡張ROLLUP](./extension-rollup/) | FIRST/LASTとOHLCの検証 |
| [JSON ROLLUP](./json-summarized-rollup/) | パス・ドキュメント全体の集計とNULL |
| [制御と状態](./ingestion-control-rollup/) | STOP/START/WAKEUP/FORCE、V$ROLLUPとgap |
| [REBUILD](./rollup-rebuild/) | 実際のサポート対象、バケット境界、訂正 |
| [パフォーマンスチューニング](./performance-tuning-rollup/) | 同じ結果を基準にコストを比較 |
| [活用シナリオ](./patterns-scenarios/) | 複数タグと元データ・集計の役割分担 |
各ページは独立した実習で、オブジェクト名を`ch6_`で区別します。
既存の業務オブジェクトと名前が重複しないことを確認し、意図的なエラー例は成功するスクリプトと分離してください。
固定時刻のデータは、示した固定区間で検索します。実習用テーブル・ROLLUPだけを削除してください。
CustomとREBUILDはStandard Edition専用です。
ROLLUPの作成や取り込みに成功したことだけで、集計が完了したと判断しないでください。
実習では名前を指定したFORCEで処理範囲に追いつき、結果を確認します。
[サポート範囲](../reference/support-scope-constraints/rollup/)と
[トラブルシューティング](../troubleshooting/rollup/)で、制約と診断を引き続き確認してください。
---
title: "6.1 ROLLUPの概要と選択基準"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/overview-use-criteria/
language: ja
kind: page
---
# 6.1 ROLLUPの概要と選択基準
ROLLUPは、生データの行から同じ集計を繰り返すコストを削減します。
元データの保持ポリシーや任意のクエリ結果のキャッシュではなく、集計に保存していない元の情報は復元できません。
## 選択基準
| 要求 | 検討する方式 |
|---|---|
| 1つの数値カラムの区間統計を繰り返し使用 | 通常のROLLUP |
| 特定の品質条件を満たすサンプルだけを集計 | 条件付きROLLUP |
| 区間の最初・最後の値が必要 | EXTENSION ROLLUP |
| 複数の集計式を別のTAGに保存 | Custom ROLLUP(Standard Edition専用) |
| JSONパスやドキュメント内の数値を集計 | JSONパスまたはドキュメント全体のROLLUP |
| 距離軸TAG | 通常の数値区間集計。ROLLUPは未サポート |
通常の数値カラムを明示して作成するROLLUPでは、SUMMARIZEDは必須ではありません。
WITH ROLLUPによる自動作成とJSONドキュメント全体の集計には、別途SUMMARIZEDの条件があります。
詳細は[作成構文](../create-delete-rollup/)を参照してください。
## 基本実習
### 1. 作成と入力
```sql
CREATE TAG TABLE ch6_basic (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_basic_ru ON ch6_basic(value) INTERVAL 1 MIN;
INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_basic VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_basic VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
```
### 2. 集計完了範囲の確認
```sql
EXEC TABLE_FLUSH(ch6_basic);
ALTER ROLLUP ch6_basic_ru FORCE;
SHOW ROLLUPGAP;
```
SHOW ROLLUPGAPはmachsqlのコマンドです。SDKではV$ROLLUPなど、サポートされるSQLクエリを使用します。
TABLE_FLUSHは保存バッファを処理し、FORCEは指定したROLLUPの処理範囲に追いつくための操作です。
継続入力中に今後到着する行まで処理を完了するという意味ではありません。
### 3. 元データとの比較
```sql
SELECT DATE_TRUNC('minute', time) AS bucket,
COUNT(value), MIN(value), MAX(value), AVG(value)
FROM ch6_basic
WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
SELECT rollup('min', 1, time) AS bucket,
COUNT(value), MIN(value), MAX(value), AVG(value)
FROM ch6_basic
WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
| バケット | COUNT(value) | MIN | MAX | AVG |
|---|---:|---:|---:|---:|
| 2026-01-01 00:00:00 | 2 | 10 | 20 | 15 |
| 2026-01-01 00:01:00 | 1 | 30 | 30 | 30 |
両方のクエリは同じ結果を返す必要があります。
DATE_TRUNCによる元データの集計が、ROLLUPの存在だけで自動的に切り替わるとは説明しません。
ROLLUPのクエリでは`rollup()`を明示します。
### 4. クリーンアップ
```sql
DROP ROLLUP ch6_basic_ru;
DROP TABLE ch6_basic;
```
## 導入前の確認
代表的なタグ数、入力量、検索頻度、許容できる集計遅延を決めます。
必要な最小の区間と元データの保持期間を先に決め、[階層設計](../target-tag-table-design/)に進んでください。
長期間の性能は本番に近いデータで測定し、この小さなサンプルの実行時間から推定しないでください。
---
title: "6.2 ROLLUP対象TAGテーブルの設計"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/target-tag-table-design/
language: ja
kind: page
---
# 6.2 ROLLUP対象TAGテーブルの設計
## ONとFROM
`ON source(column)`は元の時間軸TAGの列を集計します。
`FROM rollup_name`は既存の通常・拡張ROLLUPの統計を、より大きい区間に合算します。
Customの出力先もTAGですが、次のCustom段階は出力先TAGをSELECTするINTO...AS構文で構成します。
## 階層の実習
```sql
CREATE TAG TABLE ch6_design (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_design_sec ON ch6_design(value) INTERVAL 1 SEC;
CREATE ROLLUP ch6_design_min FROM ch6_design_sec INTERVAL 1 MIN;
CREATE ROLLUP ch6_design_hour FROM ch6_design_min INTERVAL 1 HOUR;
INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_design VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_design VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
EXEC TABLE_FLUSH(ch6_design);
ALTER ROLLUP ch6_design_sec FORCE;
ALTER ROLLUP ch6_design_min FORCE;
ALTER ROLLUP ch6_design_hour FORCE;
SELECT name, rollup('hour', 1, time) AS bucket,
SUM(value), COUNT(value), AVG(value)
FROM ch6_design
GROUP BY name, bucket ORDER BY name, bucket;
```
TEMP_01は合計60、件数3、平均20、TEMP_02は100、1、100です。
下位からFORCEを実行すると、上位が新しく作成された下位の結果も処理できます。
### 階層の制約
- 上位の間隔はソースの間隔より大きい整数倍である必要があります。同じ間隔も許可されません。
- FROMを使って通常のROLLUPを拡張ROLLUPに変更したり、その逆に変更したりすることはできません。
階層内のEXTENSION属性を一致させてください。
- JSONパス・ドキュメントモードもソースと一致する必要があります。
- 必要なクエリの最小区間より粗い統計から、より細かい元データは復元できません。
次は、それぞれ意図的に失敗する作成例です。
```sql
CREATE ROLLUP ch6_design_bad_same FROM ch6_design_min INTERVAL 1 MIN;
CREATE ROLLUP ch6_design_bad_divisor FROM ch6_design_min INTERVAL 90 SEC;
CREATE ROLLUP ch6_design_bad_ext FROM ch6_design_sec INTERVAL 1 MIN EXTENSION;
```
## 間隔と保存量の決定
すべてのタグがすべての区間に値を持つと仮定すると、論理バケット数はおおよそ
`(保持時間 / バケット間隔) × タグ数`です。1万タグの1秒バケットを365日間保持すると、約3,154億バケットになります。
実際の保存行数は部分集計・空の区間・列数の影響を受け、ディスク容量は圧縮と保存オーバーヘッドも含めて測定する必要があります。
秒単位の観測値を分単位でしか検索しない場合は、最初からすべての秒階層が必要かを検討してください。
作成間隔はSEC/MIN/HOURで表しますが、DAY/WEEK/MONTH/YEARはクエリのバケット単位です。
特に、日単位のクエリに24 HOURの保存間隔をそのまま適用できるとは考えず、[候補選択規則](../query-syntax-rollup/)を確認してください。
新しいROLLUPはソースに残る既存データも初期集計するため、初期処理量とgapを確認します。
元データの補正はFORCEで巻き戻して処理されません。[REBUILDのサポート範囲](../rollup-rebuild/)に従ってください。
## クリーンアップ
```sql
DROP ROLLUP ch6_design_hour;
DROP ROLLUP ch6_design_min;
DROP ROLLUP ch6_design_sec;
DROP TABLE ch6_design;
```
---
title: "6.3 ROLLUPの作成と削除"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/create-delete-rollup/
language: ja
kind: page
---
# 6.3 ROLLUPの作成と削除
## 作成構文
```text
CREATE ROLLUP [IF NOT EXISTS] name
ON source_tag [(column_or_json_path)]
INTERVAL n (SEC|MIN|HOUR)
[WAKEUP INTERVAL m (SEC|MIN|HOUR)]
[EXTENSION]
[WHERE predicate];
CREATE ROLLUP [IF NOT EXISTS] name
FROM source_rollup
INTERVAL n (SEC|MIN|HOUR)
[WAKEUP INTERVAL m (SEC|MIN|HOUR)]
[EXTENSION]
[WHERE predicate];
```
EXTENSIONの後に別の拡張名は指定しません。CREATEの単位はSEC/MIN/HOURであり、
クエリ関数のDAY/MONTHなどとは区別します。間隔は正数で、現在の検証上限は365日に相当する間隔です。
ソース・階層・集計モードの条件も満たす必要があります。
| 対象 | 条件 |
|---|---|
| 通常の数値カラム | サポートされる数値型を指定。SUMMARIZEDは必須ではない |
| JSONパス | 対象のJSONカラムと有効なパスを指定 |
| JSONドキュメント全体 | JSON SUMMARIZEDカラムが必要 |
| WITH ROLLUPによる自動作成 | 3番目にSUMMARIZEDカラムが必要 |
| METADATA・距離軸・TAG以外 | 通常のROLLUPの対象外 |
## 作成・重複確認・検索の実習
```sql
CREATE TAG TABLE ch6_create (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP IF NOT EXISTS ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN;
CREATE ROLLUP IF NOT EXISTS ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN;
INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_create VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_create VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
EXEC TABLE_FLUSH(ch6_create);
ALTER ROLLUP ch6_create_ru FORCE;
SELECT DISTINCT ROLLUP_NAME, COLUMN_NAME, INTERVAL_TIME, WAKEUP_INTERVAL
FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CREATE_RU';
SELECT rollup('min', 1, time) AS bucket, AVG(value)
FROM ch6_create WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
同名で再作成しても既存の定義は保持されます。IF NOT EXISTSは定義の変更や同一性の確認機能ではなく、
不正なSQLやソースの検証をすべて省略するオプションでもありません。
2つの間隔カラムは60000msで、検索結果の平均は00:00が15、00:01が30です。
IF NOT EXISTSなしで同じ名前を作成するとエラーになります。通常の実習とは別に確認してください。
```sql
CREATE ROLLUP ch6_create_ru ON ch6_create(value) INTERVAL 1 MIN;
```
## WITH ROLLUPによる自動作成
次は別のテーブルです。SECからMIN・HOURまでの基本階層を自動作成します。
```sql
CREATE TAG TABLE ch6_auto (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
) WITH ROLLUP (SEC);
SELECT DISTINCT ROLLUP_NAME, ROOT_TABLE, INTERVAL_TIME, EXT_TYPE
FROM V$ROLLUP WHERE ROOT_TABLE = 'CH6_AUTO'
ORDER BY INTERVAL_TIME;
```
INTERVAL_TIMEが1000・60000・3600000の3行が返されます。
EXTENSIONの自動作成は`WITH ROLLUP (SEC) EXTENSION`形式です。
実際の作成名はV$ROLLUPで確認し、名前の競合が自動的に解消されるとは考えないでください。
引数に応じて作成される階層が異なります。`(SEC)`はSEC・MIN・HOURの3つ、`(MIN)`はMIN・HOURの2つ、
`(HOUR)`はHOURを1つ作成します。引数の省略は`(SEC)`と同じです。
このとき、最初の段階だけが元のTAGをソースとし、次の段階は直前のROLLUPをソースとする階層で接続されます。
引数にはSEC・MIN・HOURのみ使用でき、クエリ関数が受け付けるDAYなどの単位を指定するとエラーになります。
## 削除と定義変更
他のROLLUPが参照するソースは、上位の依存オブジェクトから削除します。
Customの出力先TAGは、ジョブを削除するまでDROPできません。
定義を変更する場合は、読み取り側アプリケーションと再集計時間を考慮し、新しいオブジェクトへ切り替えるか、既存の定義を削除して再作成します。
```sql
DROP ROLLUP ch6_create_ru;
DROP TABLE ch6_create;
DROP TABLE ch6_auto CASCADE;
```
最後のCASCADEは、この実習で自動作成したROLLUPも削除します。通常の運用での削除方法のデフォルトにはしないでください。
CustomソースのCASCADEが関連ジョブを削除しても、ユーザーの出力先TAGまで自動削除するという意味ではありません。
条件付き・拡張・JSON・Customの実習は各節で独立して提供します。
完全な構文は[SQLリファレンス](../../reference/sql/syntax/rollup-syntax/)を参照してください。
---
title: "6.4 ROLLUPのクエリ構文"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/query-syntax-rollup/
language: ja
kind: page
---
# 6.4 ROLLUPのクエリ構文
## 明示的なROLLUPクエリ
```text
rollup(time_unit, period, basetime_column [, origin])
```
| 引数 | 仕様 |
|---|---|
| time_unit | SECOND/SEC、MINUTE/MIN、HOUR、DAY、WEEK、MONTH、YEAR。大文字・小文字は区別しない |
| period | 正の整数リテラル。カラムやパラメータープレースホルダーは不可 |
| basetime_column | 元の時間軸TAGのBASETIMEカラム |
| origin | 省略時はタイムゾーンオフセットを反映したデフォルト基準点。明示時は単位別の制約を確認 |
戻り値はDATETIMEのバケットです。保存済み集計の最小間隔より細かい結果は復元できません。
適用可能なROLLUPがない場合は、生データのスキャンへ自動的に切り替わらず、エラーになります。
元データの集計が必要なら、DATE_TRUNC/DATE_BIN + GROUP BYのクエリを別途作成してください。
## 準備と基本クエリ
```sql
CREATE TAG TABLE ch6_query (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_query_sec ON ch6_query(value) INTERVAL 1 SEC;
INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_query VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_query VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
EXEC TABLE_FLUSH(ch6_query);
ALTER ROLLUP ch6_query_sec FORCE;
SELECT name, rollup('min', 1, time) AS bucket,
COUNT(value), SUM(value), MIN(value), MAX(value), AVG(value)
FROM ch6_query
WHERE time >= TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND time < TO_DATE('2026-01-01 00:02:00', 'YYYY-MM-DD HH24:MI:SS')
GROUP BY name, bucket ORDER BY name, bucket;
```
TEMP_01の00:00はCOUNT=2、SUM=30、AVG=15、00:01は1、30、30です。
TEMP_02の00:00は1、100、100です。SELECTでnameを返す場合は、GROUP BYにもnameを指定します。
nameを省略すると複数タグをまとめた集計になるため、単位の異なるセンサーを混在させないでください。
## 候補選択とヒント
1. ROLLUP_TABLEヒントがある場合は、その候補の互換性を検査します。
2. 自動選択では、集計カラム・JSONパス・モードと要求間隔に合う候補を探します。
3. 条件なしの候補を先に探し、なければ条件付き候補を含めて検索します。
4. 適用可能な最大の間隔を選び、同じ間隔では先に登録された候補を維持します。
通常か拡張かだけで「通常が常に優先される」と断定しないでください。
条件付きROLLUPしかない場合はフィルタリング済みデータが自動選択され得るため、結果が表すサンプル集合を確認します。
特定の集計を必ず使用する必要がある場合は、ヒントを明示してください。
```sql
SELECT /*+ ROLLUP_TABLE(ch6_query_sec) */
rollup('min', 1, time) AS bucket, AVG(value)
FROM ch6_query WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
### 保存候補の間隔とクエリのバケット
現在の候補間隔検査では、SEC要求をperiod秒、MIN要求をperiod分として計算します。
HOURおよびDAY/WEEK/MONTH/YEAR要求は、候補選択段階でperiod時間を基準に検査し、
選択した統計を要求されたカレンダー・時間バケットへ再集計します。
したがって、`rollup('day', 1, time)`のために24 HOUR ROLLUPを作成すれば自動的に使用できるとは考えないでください。
この要求では1時間の基準に合うHOUR/MIN/SEC候補を検討します。
作成時のINTERVALと結果バケットの意味を区別し、実際の実行計画を確認してください。
## 集計関数とサンプル
通常の数値ROLLUPはMIN、MAX、SUM、COUNT、AVG、SUMSQをサポートします。
ROLLUPクエリのFIRST/LASTにはEXTENSIONが必要です。
Customの結果は通常のTAGに保存されるため、[Customの再集計](../custom-rollup/)の合計・件数の規則を使用します。
JSONドキュメント全体の集計におけるCOUNTは、[JSONの節](../json-summarized-rollup/)で別途説明します。
### SUMSQと分散・標準偏差
ROLLUPクエリはSTDDEV、STDDEV_POP、VARIANCE、VAR_POPを直接サポートしていません。
`rollup()`クエリでこれらの関数を使用すると、
`ERR-02816: Only rollup column with aggregate function can be referenced in ROLLUP SELECT query.`
が発生します。分散と標準偏差は、区間別の結果をそのまま加算できないためです。
2つの区間の標準偏差を平均しても、全区間の標準偏差にはなりません。
代わりにROLLUPは、値の平方和であるSUMSQをCOUNT、SUMと併せて保存します。
この3つはすべて加算できるため、保存間隔より大きいバケットに再集計しても有効であり、クエリ時に分散と標準偏差を計算できます。
SUMSQは通常のROLLUPとEXTENSION ROLLUPの両方に含まれます。
| 値 | 計算式 |
|---|---|
| 母分散 | `SUMSQ/N - (SUM/N)^2` |
| 母標準偏差 | 母分散の平方根 |
| 標本分散 | `(SUMSQ - SUM^2/N) / (N-1)` |
| 標本標準偏差 | 標本分散の平方根 |
Nは`COUNT(value)`であり、NULLを除いた有効値の個数です。
ROLLUPのクエリブロックにはサポートされる集計だけを置き、分散と標準偏差はインラインビューの外で計算します。
COUNT、SUM、SUMSQを一度だけ読み取り、派生計算を分離するため、計算式を変更してもROLLUPクエリ部分はそのまま使用できます。
```sql
SELECT bucket, n, s, sq,
sq/n - POWER(s/n, 2) AS var_pop,
SQRT(sq/n - POWER(s/n, 2)) AS stddev_pop
FROM (
SELECT rollup('min', 1, time) AS bucket,
COUNT(value) AS n,
SUM(value) AS s,
SUMSQ(value) AS sq
FROM ch6_query WHERE name = 'TEMP_01'
GROUP BY bucket
) t
ORDER BY bucket;
```
00:00バケットの値は10と20なので、n=2、s=30、sq=500、母分散25、母標準偏差5です。
00:01バケットは値が1つなので、母分散と母標準偏差は0です。
標本分散の分母は`N-1`のため、値が1つのバケットを先に判別する必要があります。
この判定もインラインビューの外で行います。`ELSE NULL`を明示すると`ERR-02042`が発生するため、`ELSE`を省略します。
```sql
SELECT bucket, n,
CASE WHEN n > 1
THEN (sq - POWER(s, 2)/n) / (n - 1)
END AS var_samp
FROM (
SELECT rollup('min', 1, time) AS bucket,
COUNT(value) AS n,
SUM(value) AS s,
SUMSQ(value) AS sq
FROM ch6_query WHERE name = 'TEMP_01'
GROUP BY bucket
) t
ORDER BY bucket;
```
00:00バケットの標本分散は50、値が1つの00:01バケットはNULLです。
値が1つの区間を結果から除くには、インラインビューの外で`WHERE n > 1`を使用します。
元テーブルの`VARIANCE`と`STDDEV`は同じ区間でNULLではなく0を返すため、両方の結果を併用する場合は表示ポリシーを合わせてください。
上の例の値では、元テーブルに`VAR_POP`、`STDDEV_POP`、`VARIANCE`、`STDDEV`を直接使用した結果と一致します。
ただし、2つの計算式は平均が大きく偏差が小さいほど桁落ちが発生します。
例えば、値が100000付近で小数点以下だけ変動する場合、`SUMSQ/N`と`(SUM/N)^2`がほぼ同じ大きさになり、減算結果の有効桁数が減少します。
浮動小数点誤差で分散がごく小さな負数になると、`SQRT`の結果も無効になります。
精度が重要な区間では、元テーブルの`STDDEV`、`VAR_POP`の結果と比較し、使用可能な範囲を確認してください。
## カレンダー単位とorigin
同じ準備データを使用し、月単位の結果と月曜日を基準にした週単位を確認します。
```sql
SELECT rollup('month', 1, time, '2000-01-01 00:00:00') AS bucket,
SUM(value), COUNT(value), AVG(value)
FROM ch6_query WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
SELECT rollup('week', 1, time, '1970-01-05 00:00:00') AS bucket, AVG(value)
FROM ch6_query WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
月単位のクエリは2026-01-01バケットにSUM=60、COUNT=3、AVG=20を返します。
月・年のoriginはタイムゾーン解釈後に月の1日である必要があり、結果はその月境界の午前0時です。
任意の日付や時刻オフセットで月次業務の開始時刻を移す機能と解釈しないでください。
日・週などの固定間隔のoriginと、月・年のカレンダー計算を区別します。
文字列の意味は接続タイムゾーンと併せて確認してください。
DSTが自動的に業務カレンダーに合うと考えず、境界前後の元データのDATE_BIN集計と比較してください。
保存済み集計を分割する必要があるoriginや検索境界では、元データと同じ結果を期待できるか検証します。
## クリーンアップ
```sql
DROP ROLLUP ch6_query_sec;
DROP TABLE ch6_query;
```
---
title: "6.5 条件付きROLLUP"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/conditional-rollup/
language: ja
kind: page
---
# 6.5 条件付きROLLUP
## 元データをフィルタリングしてから集計
条件付きROLLUPは、元データの品質・状態の条件を適用した統計を保持します。
計算済みの平均から後で不良サンプルだけを除く処理とは異なります。
条件で使用したqualityカラム自体が集計結果に保持されるわけでもありません。
## 1. テーブルと2つのROLLUPの準備
```sql
CREATE TAG TABLE ch6_condition (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_condition_all
ON ch6_condition(value) INTERVAL 1 MIN EXTENSION;
CREATE ROLLUP ch6_condition_good
ON ch6_condition(value) INTERVAL 1 MIN EXTENSION WHERE quality = 1;
INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_condition VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_condition VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
INSERT INTO ch6_condition VALUES
('TEMP_01', TO_DATE('2026-01-01 00:00:50', 'YYYY-MM-DD HH24:MI:SS'), 90.0, 0);
EXEC TABLE_FLUSH(ch6_condition);
ALTER ROLLUP ch6_condition_all FORCE;
ALTER ROLLUP ch6_condition_good FORCE;
```
## 2. 元データの条件とROLLUPの比較
```sql
SELECT DATE_TRUNC('minute', time) AS bucket, COUNT(value), AVG(value),
MIN(value), MAX(value), FIRST(time, value), LAST(time, value)
FROM ch6_condition
WHERE name = 'TEMP_01' AND quality = 1
GROUP BY bucket ORDER BY bucket;
SELECT /*+ ROLLUP_TABLE(ch6_condition_good) */
rollup('min', 1, time) AS bucket, COUNT(value), AVG(value),
MIN(value), MAX(value), FIRST(time, value), LAST(time, value)
FROM ch6_condition WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
SELECT /*+ ROLLUP_TABLE(ch6_condition_all) */
rollup('min', 1, time) AS bucket, COUNT(value), AVG(value),
MIN(value), MAX(value), FIRST(time, value), LAST(time, value)
FROM ch6_condition WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
| バケット・集合 | COUNT | AVG | MIN | MAX | FIRST | LAST |
|---|---:|---:|---:|---:|---:|---:|
| 00:00 全件 | 3 | 40 | 10 | 90 | 10 | 90 |
| 00:00 quality=1 | 2 | 15 | 10 | 20 | 10 | 20 |
| 00:01 両集合共通 | 1 | 30 | 30 | 30 | 30 | 30 |
このサンプルでは、不良値が区間の最後にあるためLASTも異なります。
FIRST/LASTが返すのは、時刻と値の組ではなく、選択されたvalueです。
## 候補の明示的な選択
この例では、全件統計と正常値の統計の結果集合を固定するためにヒントを使用します。
自動選択は条件なしの候補を優先しますが、条件付き候補しかない場合はフィルタリング済み統計を選択し得ます。
「条件付きROLLUPは常に無視される」「EXTENSIONでは常にヒントが必須」という規則と解釈しないでください。
## 構文と制約
通常のROLLUPのフィルターは、INTERVAL・EXTENSIONの後のWHEREに記述します。
比較、BETWEEN、IN、LIKE、論理演算、サポートされるスカラー関数を使用できますが、
サブクエリ、集計関数、タグ名PRIMARY KEYの条件はサポートしていません。
CustomはSELECT内のWHEREを使用するため、構文を混同しないでください。
## 状態確認とクリーンアップ
```sql
SELECT DISTINCT ROLLUP_NAME, PREDICATE, ENABLED
FROM V$ROLLUP WHERE ROOT_TABLE = 'CH6_CONDITION';
DROP ROLLUP ch6_condition_good;
DROP ROLLUP ch6_condition_all;
DROP TABLE ch6_condition;
```
業務の品質基準が変わったら、条件と再集計計画も更新してください。
既存の集計が新しい条件に自動的に切り替わることはありません。
[制御](../ingestion-control-rollup/)と[再構築範囲](../rollup-rebuild/)を確認してください。
---
title: "6.6 Custom ROLLUP"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/custom-rollup/
language: ja
kind: page
---
# 6.6 Custom ROLLUP
Standard Edition専用
## Customと通常のROLLUP
Custom ROLLUPは、SELECTの増分集計結果を事前作成した出力先TAGに追加します。
通常のROLLUPの内部統計を`rollup()`で読む方式とは異なり、出力先TAGを直接検索して部分集計を再結合する必要があります。
Cluster Editionでは作成できません。
```text
CREATE ROLLUP [IF NOT EXISTS] name
INTO (destination_tag)
AS (SELECT ... FROM source_tag [WHERE ...] GROUP BY ...)
INTERVAL n (SEC|MIN|HOUR)
[WAKEUP INTERVAL m (SEC|MIN|HOUR)];
```
ソースは1つの時間軸TAGで、JOIN・FROMサブクエリは使用できません。
出力先は事前作成したTAGで、SELECTのカラム順序と型に互換性が必要です。
SELECT内のWHEREは使用できますが、BASETIMEの直接条件は許可されません。
通常のROLLUPのように、INTERVALの後に外側のWHEREを付けないでください。
作成間隔とSELECTが計算する時間バケットを一致させてください。
ジョブは新しい入力だけを処理するため、同じバケットに複数の結果行が存在し得ます。
行数をバケット数と解釈しないでください。
## 1. 合計と有効件数の実習
```sql
CREATE TAG TABLE ch6_custom_src (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE
);
CREATE TAG TABLE ch6_custom_dst (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME,
sum_value DOUBLE, valid_count LONG, total_count LONG
);
CREATE ROLLUP ch6_custom_ru INTO (ch6_custom_dst)
AS (
SELECT name, DATE_TRUNC('minute', time) AS time,
SUM(value), COUNT(value), COUNT(*)
FROM ch6_custom_src
GROUP BY name, time
) INTERVAL 1 MIN;
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:05', 'YYYY-MM-DD HH24:MI:SS'), 10);
EXEC TABLE_FLUSH(ch6_custom_src);
ALTER ROLLUP ch6_custom_ru FORCE;
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:10', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:15', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:20', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:25', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:35', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:40', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:45', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch6_custom_src VALUES ('S1', TO_DATE('2026-01-01 00:00:55', 'YYYY-MM-DD HH24:MI:SS'), NULL);
EXEC TABLE_FLUSH(ch6_custom_src);
ALTER ROLLUP ch6_custom_ru FORCE;
SELECT name, DATE_TRUNC('minute', time) AS bucket,
SUM(value), COUNT(value), COUNT(*), AVG(value)
FROM ch6_custom_src
GROUP BY name, bucket ORDER BY name, bucket;
SELECT name, time, SUM(sum_value) AS sum_value,
SUM(valid_count) AS valid_count, SUM(total_count) AS total_count,
CASE WHEN SUM(valid_count) = 0 THEN NULL
ELSE SUM(sum_value) / SUM(valid_count) END AS avg_value
FROM ch6_custom_dst
GROUP BY name, time ORDER BY name, time;
```
1バケットの合計は180、有効値は10個、全行数は11、平均は18です。
部分平均10と20を単純平均した15とは異なります。
NULLを平均の分母に含めないようCOUNT(value)を使用し、NULLを含む行数はCOUNT(*)で別途保持します。
すべての値がNULLのバケットも処理する場合は、有効件数0で除算しない結果ポリシーも決めてください。
### サンプル比率と時間稼働率
条件を満たすサンプル数を全サンプル数で割った値は、サンプル比率です。
時間稼働率として解釈するには、観測間隔・欠損処理・状態の継続時間を反映する必要があります。
比率も部分比率を平均せず、分子と分母をそれぞれ合算します。
## 2. OHLCVと1分→10分のCustom階層
独立した実習です。FIRST/LASTの再集計のため、元の最初・最後の観測時刻も保存します。
```sql
CREATE TAG TABLE ch6_ticks (
code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME,
price DOUBLE, volume DOUBLE
);
CREATE TAG TABLE ch6_candle_min (
code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME,
open_price DOUBLE, high_price DOUBLE, low_price DOUBLE, close_price DOUBLE,
volume DOUBLE, cnt LONG, firsttime DATETIME, lasttime DATETIME
);
CREATE TAG TABLE ch6_candle_10m (
code VARCHAR(20) PRIMARY KEY, time DATETIME BASETIME,
open_price DOUBLE, high_price DOUBLE, low_price DOUBLE, close_price DOUBLE,
volume DOUBLE, cnt LONG, firsttime DATETIME, lasttime DATETIME
);
CREATE ROLLUP ch6_candle_ru_min INTO (ch6_candle_min)
AS (
SELECT code, DATE_TRUNC('minute', time) AS time,
FIRST(time, price), MAX(price), MIN(price), LAST(time, price),
SUM(volume), COUNT(*), MIN(time), MAX(time)
FROM ch6_ticks
GROUP BY code, time
) INTERVAL 1 MIN;
CREATE ROLLUP ch6_candle_ru_10m INTO (ch6_candle_10m)
AS (
SELECT code, DATE_BIN('min', 10, time, TO_DATE('2000-01-01 00:00:00')) AS time,
FIRST(firsttime, open_price), MAX(high_price),
MIN(low_price), LAST(lasttime, close_price),
SUM(volume), SUM(cnt), MIN(firsttime), MAX(lasttime)
FROM ch6_candle_min
GROUP BY code, time
) INTERVAL 10 MIN;
INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:00:00'), 100, 2);
INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:00:30'), 105, 3);
INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:01:00'), 103, 1);
INSERT INTO ch6_ticks VALUES ('AAPL', TO_DATE('2026-01-01 09:01:30'), 99, 4);
EXEC TABLE_FLUSH(ch6_ticks);
ALTER ROLLUP ch6_candle_ru_min FORCE;
EXEC TABLE_FLUSH(ch6_candle_min);
ALTER ROLLUP ch6_candle_ru_10m FORCE;
SELECT code, time,
FIRST(firsttime, open_price), MAX(high_price),
MIN(low_price), LAST(lasttime, close_price), SUM(volume), SUM(cnt)
FROM ch6_candle_10m
GROUP BY code, time ORDER BY code, time;
```
09:00の10分バケットは、Open=100、High=105、Low=99、Close=99、volume=10、cnt=4です。
価格や取引量がNULLの場合は、どの行の時刻と値を使用するか、別途規則とテストが必要です。
同時刻の複数の取引にも業務上の順序がある場合は、追加の識別基準を設計してください。
この10分Customは作成・検索の例です。現在のREBUILDのCustom時間範囲処理でサポートする間隔と同じだと考えないでください。
[REBUILDの制限](../rollup-rebuild/)を確認してください。
## 状態とクリーンアップ
作成後は自動的に開始するため、直後にSTARTを繰り返さないでください。
STOP/STARTとFORCEはジョブの状態に応じて呼び出します。
ジョブが存在する出力先TAGのDROPは拒否されます。
```sql
SELECT DISTINCT ROLLUP_NAME, ROLLUP_TABLE, ROOT_TABLE, EXT_TYPE,
INTERVAL_TIME, WAKEUP_INTERVAL
FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CUSTOM_RU';
DROP ROLLUP ch6_candle_ru_10m;
DROP ROLLUP ch6_candle_ru_min;
DROP TABLE ch6_candle_10m;
DROP TABLE ch6_candle_min;
DROP TABLE ch6_ticks;
DROP ROLLUP ch6_custom_ru;
DROP TABLE ch6_custom_dst;
DROP TABLE ch6_custom_src;
```
EXT_TYPE=2はCustomを表し、PREDICATEにはSELECT本文が記録されます。
クリーンアップでは、実行した実習のオブジェクトだけを対象にしてください。
元データの補正と上位の再集計の再試行・完了確認は、[制御と状態](../ingestion-control-rollup/)およびREBUILDの手順に従ってください。
---
title: "6.7 拡張ROLLUPとFIRST/LAST"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/extension-rollup/
language: ja
kind: page
---
# 6.7 拡張ROLLUPとFIRST/LAST
## EXTENSIONと元データのFIRST/LASTの違い
EXTENSIONはROLLUPに最初・最後の値と関連する時刻情報を追加します。
通常の元データのGROUP BYでFIRST/LASTを使うことと、保存済みROLLUPからFIRST/LASTを取得することは異なります。
後者には、適用可能な拡張ROLLUPが必要です。
EXTENSIONが追加するのは最初・最後の値と時刻だけです。
MIN、MAX、SUM、COUNT、平方和のSUMSQは通常のROLLUPにも保存されます。
SUMSQから分散と標準偏差を計算する方法は、
[SUMSQと分散・標準偏差](../query-syntax-rollup/#query-sumsq-stddev-rollup)を参照してください。
## 準備と入力
```sql
CREATE TAG TABLE ch6_ext (
code VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
price DOUBLE
);
CREATE ROLLUP ch6_ext_first
ON ch6_ext(price) INTERVAL 1 MIN EXTENSION;
CREATE ROLLUP ch6_ext_plain
ON ch6_ext(price) INTERVAL 1 MIN;
INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100);
INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:10', 'YYYY-MM-DD HH24:MI:SS'), 105);
INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:20', 'YYYY-MM-DD HH24:MI:SS'), 99);
INSERT INTO ch6_ext VALUES ('AAPL', TO_DATE('2026-01-01 09:00:30', 'YYYY-MM-DD HH24:MI:SS'), 103);
EXEC TABLE_FLUSH(ch6_ext);
ALTER ROLLUP ch6_ext_first FORCE;
ALTER ROLLUP ch6_ext_plain FORCE;
```
## 元データとOHLCの比較
```sql
SELECT DATE_TRUNC('minute', time) AS bucket,
FIRST(time, price) AS open_price, MAX(price) AS high_price,
MIN(price) AS low_price, LAST(time, price) AS close_price
FROM ch6_ext WHERE code = 'AAPL'
GROUP BY bucket ORDER BY bucket;
SELECT /*+ ROLLUP_TABLE(ch6_ext_first) */
rollup('min', 1, time) AS bucket,
FIRST(time, price) AS open_price, MAX(price) AS high_price,
MIN(price) AS low_price, LAST(time, price) AS close_price
FROM ch6_ext WHERE code = 'AAPL'
GROUP BY bucket ORDER BY bucket;
```
両方のクエリは、09:00バケットにOpen=100、High=105、Low=99、Close=103を返します。
ROLLUPのFIRST/LASTの第1引数にはBASETIME、第2引数には集計対象カラムを使用します。
同じ時刻に複数の値がある場合に業務上の追加の順序が必要なら、別途設計してください。
## 通常の候補と拡張候補が共存する場合
通常のROLLUPが拡張ROLLUPより無条件に優先されるわけではありません。
同じ条件・間隔の候補は、登録順序の影響を受けます。
この例では拡張を先に作成していますが、特定候補を使用する必要がある場合は上記のように明示してください。
拡張だけが適用可能な環境では、ヒントなしで選択される場合もあります。
次は通常のROLLUPを強制するため、意図的に失敗するクエリです。
```sql
SELECT /*+ ROLLUP_TABLE(ch6_ext_plain) */
rollup('min', 1, time) AS bucket, FIRST(time, price)
FROM ch6_ext WHERE code = 'AAPL'
GROUP BY bucket;
```
自動階層に拡張が必要なら、別のテーブルのCREATEで`WITH ROLLUP (SEC) EXTENSION`を使用します。
FROMで階層を作成する場合も、拡張属性を一致させる必要があります。
Custom OHLCVの再集計は[Customの実習](../custom-rollup/)を参照してください。
## クリーンアップ
```sql
DROP ROLLUP ch6_ext_plain;
DROP ROLLUP ch6_ext_first;
DROP TABLE ch6_ext;
```
---
title: "6.8 JSON SUMMARIZED ROLLUP"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/json-summarized-rollup/
language: ja
kind: page
---
# 6.8 JSON SUMMARIZED ROLLUP
## JSONパスとドキュメント全体の集計
JSONパスROLLUPは指定パスの数値を集計します。
ドキュメント全体のROLLUPは、JSON SUMMARIZEDカラム内の数値パスごとの統計を保持します。
パスが存在しない値、JSON null、SQL NULL、配列を同じサンプルとして解釈しないでください。
## 準備
```sql
CREATE TAG TABLE ch6_json (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value JSON SUMMARIZED
);
CREATE ROLLUP ch6_json_metric ON ch6_json(value.metric) INTERVAL 1 MIN;
CREATE ROLLUP ch6_json_whole ON ch6_json(value) INTERVAL 1 MIN;
INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:00'),
'{"metric":10,"nested":{"x":2},"status":"OK","items":[1,2]}');
INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:10'),
'{"metric":20,"nested":{"x":4},"status":"WARN","items":[3,4]}');
INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:20'),
'{"metric":null,"status":false}');
INSERT INTO ch6_json VALUES ('S1', TO_DATE('2026-01-01 00:00:30'), NULL);
EXEC TABLE_FLUSH(ch6_json);
ALTER ROLLUP ch6_json_metric FORCE;
ALTER ROLLUP ch6_json_whole FORCE;
```
## パス集計の比較
```sql
SELECT DATE_TRUNC('minute', time) AS bucket,
COUNT(JSON_EXTRACT_DOUBLE(value, '$.metric')),
AVG(JSON_EXTRACT_DOUBLE(value, '$.metric'))
FROM ch6_json WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
SELECT /*+ ROLLUP_TABLE(ch6_json_metric) */
rollup('min', 1, time) AS bucket,
COUNT(value.metric), AVG(value.metric)
FROM ch6_json WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
SELECT /*+ ROLLUP_TABLE(ch6_json_metric) */
rollup('min', 1, time) AS bucket, AVG(value->'$.metric')
FROM ch6_json WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
```
metricの有効な数値サンプルは2個で、平均は15です。dotとarrowは同じパスを表します。
特定の配列要素をパスで指定することと、ドキュメント全体の集計が配列を自動展開することは異なります。
パス宣言の例として`value.items[0]."metric-id"`を使用できますが、対象のJSON構造と数値サンプルが実際に存在することを先に確認してください。
## ドキュメント全体の集計とCOUNT
```sql
SELECT COUNT(*) AS raw_rows, COUNT(value) AS raw_documents FROM ch6_json;
SELECT /*+ ROLLUP_TABLE(ch6_json_whole) */
rollup('min', 1, time) AS bucket,
COUNT(value), AVG(value), MIN(value), MAX(value), SUM(value)
FROM ch6_json WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
```
元データのCOUNT(*)は4、COUNT(value)は3です。
ドキュメント全体のROLLUPのCOUNT(value)は、保存済みのドキュメント集計件数を合算します。
現在、この集計の件数は元データのCOUNT(*)で作成されるため、上記のように数値パスを持つドキュメントとSQL NULLが混在するバケットでは4です。
通常の元データのCOUNT(value)のNULL除外規則を、そのまま適用しないでください。
AVGの結果はmetricが15、nested.xが3で、各パスの有効な数値サンプルから計算します。
文字列・ブール値・JSON null・配列は数値集計から除外され、数値でないパスはnullまたは省略として現れる場合があります。
JSONシリアライズ時のキー順序を、固定の文字列結果として比較しないでください。
数値パスがないドキュメントやSQL NULLだけの区間は、別のサンプルを作成して確認してください。
JSONパス集計とドキュメント全体の集計は候補モードが異なります。
異なるモードのROLLUPをヒントで強制しても同じ結果になるとは考えないでください。
無効なJSONは入力エラーになります。
## クリーンアップ
```sql
DROP ROLLUP ch6_json_whole;
DROP ROLLUP ch6_json_metric;
DROP TABLE ch6_json;
```
---
title: "6.9 ROLLUPの制御と状態確認"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/ingestion-control-rollup/
language: ja
kind: page
---
# 6.9 ROLLUPの制御と状態確認
## ジョブの状態と処理完了
ROLLUPは作成時に自動的に開始します。直後にSTARTを繰り返したり、停止済みのジョブに再度STOPを実行したりすると、状態エラーが発生する場合があります。
次の実習では、作成 → STOP → 入力 → START → WAKEUP → FORCEの順に状態を区別します。
```sql
CREATE TAG TABLE ch6_control (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_control_ru ON ch6_control(value)
INTERVAL 1 MIN WAKEUP INTERVAL 10 SEC;
ALTER ROLLUP ch6_control_ru STOP;
INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_control VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_control VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
EXEC TABLE_FLUSH(ch6_control);
SELECT DISTINCT ROLLUP_NAME, ENABLED, INTERVAL_TIME, WAKEUP_INTERVAL
FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU';
ALTER ROLLUP ch6_control_ru START;
ALTER ROLLUP ch6_control_ru WAKEUP;
ALTER ROLLUP ch6_control_ru FORCE;
SELECT rollup('min', 1, time) AS bucket, AVG(value)
FROM ch6_control WHERE name = 'TEMP_01'
GROUP BY bucket ORDER BY bucket;
```
停止状態のENABLEDは0、INTERVAL_TIMEは60000ms、WAKEUP_INTERVALは10000msです。
最後のクエリは、TEMP_01の00:00の平均15と00:01の平均30を返します。
| コマンド | 目的 | 完了の意味 |
|---|---|---|
| STOP | ジョブを停止 | 以後の未処理入力は残る |
| START | 停止したジョブを再開 | 処理位置から続行 |
| WAKEUP | ジョブを起動 | 処理完了は待たない |
| FORCE | 対象ソースの処理範囲に追いつくまで待機 | 過去の修正分の再計算や将来の入力完了ではない |
| ROLLUP_REBUILD | サポート対象の過去バケットを再計算 | 元データの補正後に集計を再構築 |
SQL ALTERの代わりに、名前を指定した`EXEC ROLLUP_START(name)`、`ROLLUP_STOP(name)`、
`ROLLUP_FORCE(name)`も使用できます。同じ状態遷移を両方の形式で続けて実行しないでください。
名前を指定しない一括制御と、特定ジョブの制御の範囲を混同しないでください。
## WAKEUP INTERVAL
省略時は作成時のINTERVALと同じです。正数で、集計間隔以下であり、集計間隔を割り切れる値にする必要があります。
起動頻度を高めると遅延を減らせますが、処理負荷も増加します。
```sql
ALTER ROLLUP ch6_control_ru SET WAKEUP INTERVAL 5 SEC;
SELECT DISTINCT ROLLUP_NAME, INTERVAL_TIME, WAKEUP_INTERVAL
FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU';
```
WAKEUP_INTERVALが5000msになります。次は60秒の約数でない値を使う意図的なエラーです。
```sql
ALTER ROLLUP ch6_control_ru SET WAKEUP INTERVAL 7 SEC;
```
## V$ROLLUPの読み方
| カラム | 意味 |
|---|---|
| ROLLUP_NAME | 制御するジョブ名 |
| ROLLUP_TABLE | 集計先テーブル。Customではユーザーの出力先TAG |
| SOURCE_TABLE, ROOT_TABLE | 直接のソースと、ジョブを解釈するための元データの関係 |
| COLUMN_NAME | 通常集計・パス集計の対象カラム |
| INTERVAL_TIME, WAKEUP_INTERVAL | ミリ秒単位の作成間隔・実行間隔 |
| LAST_WAKEUP_TIME, NEXT_WAKEUP_TIME | 直前の起動時刻と次の予定時刻 |
| EXT_TYPE | 0: 通常、1: 拡張、2: Custom |
| PREDICATE | 通常の条件式、またはCustomのSELECT本文 |
| ENABLED | ジョブの有効状態 |
| RUN_STATE | `I`: 初期、`S`: 待機、`R`: 処理中 |
| END_RID | ソースの処理位置 |
| LAST_ELAPSED_MSEC | 直前の処理時間(ms) |
| DATABASE_NAME, USER_ID | データベース・所有者の識別 |
```sql
SELECT ROLLUP_NAME, ROLLUP_TABLE, SOURCE_TABLE, ROOT_TABLE,
INTERVAL_TIME, WAKEUP_INTERVAL, LAST_WAKEUP_TIME, NEXT_WAKEUP_TIME,
ENABLED, RUN_STATE, LAST_ELAPSED_MSEC
FROM V$ROLLUP WHERE ROLLUP_NAME = 'CH6_CONTROL_RU'
ORDER BY ROLLUP_NAME;
SHOW ROLLUPGAP;
```
SHOW ROLLUPGAPはmachsql専用のクライアントコマンドです。SDKの通常のSQL APIには送信しないでください。
GAPはソースとROLLUPの処理RIDの差です。時間遅延そのものではなく、すべての階層・関連ノードの状態と併せて確認します。
gap=0でも、集計済みの元データに対する補正が反映されたとは限りません。
継続入力中の値は観測時点で変わるため、再現実習では入力を止めて比較します。
停止中に元データが保持ポリシーで削除された場合、STARTだけでは復元できません。
FORCEは下位から上位の順に実行し、失敗したら最初のエラー、状態、ソースにアクセス可能かを確認してください。
## クリーンアップ
```sql
DROP ROLLUP ch6_control_ru;
DROP TABLE ch6_control;
```
詳細なコマンド仕様は[EXECリファレンス](../../reference/sql/syntax/execute-procedure-syntax/)と
[ROLLUPのトラブルシューティング](../../troubleshooting/rollup/)を参照してください。
---
title: "6.10 ROLLUP_REBUILD"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/rollup-rebuild/
language: ja
kind: page
---
# 6.10 ROLLUP_REBUILD
ROLLUP_REBUILDは、元データの過去の値を補正した後に集計を再計算するプロシージャで、Standard Edition専用です。
FORCEとは異なり、影響を受けるバケットを削除・再作成します。
すべてのROLLUP定義を任意に再構築する汎用コマンドではありません。
## サポート対象の事前確認
| 対象 | 現在の対応 |
|---|---|
| WITH ROLLUPで作成した完全なSEC→MIN→HOUR階層 | 基本数値・拡張・ドキュメント全体JSONの処理 |
| 元データに接続されたサポート対象のCustomツリー | 1 SEC・1 MIN・1 HOURの間隔と、再構築境界に合うSELECTを確認 |
| 任意の名前・間隔で手動作成した通常のROLLUP | 自動階層と同じ対応を前提にしない |
| SECがないMIN/HOURだけの自動階層 | 完全な基本階層とは見なさない |
| 10 MINなど別の間隔のCustom | 現在の時間境界生成処理では未サポート |
| Cluster Edition | 未サポート |
CustomのSELECTが作るバケット、INTERVAL、基準タイムゾーンは、再構築境界と一致する必要があります。
未サポートのジョブがツリーに混在していないかを先に調べてください。
Customで作成できる式・間隔を、この関数ですべて再構築できるとは考えないでください。
## 時間引数とバケット境界
時刻文字列、または定数文字列を使用するTO_DATEを指定します。
一般的なDATETIME式全体を評価する処理ではないため、NOWの算術式やバインドパラメーターで例を作成しないでください。
開始時刻と終了時刻が属するバケットを両方含め、バケット全体に範囲を広げます。
1分段階で00:00:30~00:01:00を指定すると、00:00と00:01の2バケット、
つまり[00:00:00, 00:02:00)の範囲が再計算されます。
開始=終了でもその時刻のバケットを再計算し、開始が終了より大きい場合はエラーになります。
上位の時間段階では、さらに広いバケットに拡張されます。
## 基本階層とCustomの訂正実習
### 1. 準備と初回集計
```sql
CREATE TAG TABLE ch6_rebuild (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE SUMMARIZED
) WITH ROLLUP (SEC);
CREATE TAG TABLE ch6_rebuild_dst (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, sum_value DOUBLE, cnt LONG
);
CREATE ROLLUP ch6_rebuild_custom INTO (ch6_rebuild_dst)
AS (
SELECT name, DATE_TRUNC('minute', time) AS time, SUM(value), COUNT(value)
FROM ch6_rebuild GROUP BY name, time
) INTERVAL 1 MIN;
INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:00:00'), 1);
INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:00:30'), 200);
INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:01:00'), 300);
INSERT INTO ch6_rebuild VALUES ('S1', TO_DATE('2026-01-01 00:01:30'), 4);
EXEC TABLE_FLUSH(ch6_rebuild);
SELECT DISTINCT ROLLUP_NAME, INTERVAL_TIME FROM V$ROLLUP
WHERE ROOT_TABLE = 'CH6_REBUILD' ORDER BY INTERVAL_TIME, ROLLUP_NAME;
ALTER ROLLUP _CH6_REBUILD_ROLLUP_SEC FORCE;
ALTER ROLLUP _CH6_REBUILD_ROLLUP_MIN FORCE;
ALTER ROLLUP _CH6_REBUILD_ROLLUP_HOUR FORCE;
ALTER ROLLUP ch6_rebuild_custom FORCE;
SELECT rollup('min', 1, time) AS bucket, AVG(value)
FROM ch6_rebuild WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
```
制御コマンドの自動生成名が、上のV$ROLLUPの結果と一致することを確認してください。
他のオブジェクト名を推測して実行しないでください。最初の分平均は100.5と152です。
### 2. 元データの補正と再構築
```sql
UPDATE ch6_rebuild SET value = 20
WHERE name = 'S1' AND time = TO_DATE('2026-01-01 00:00:30');
UPDATE ch6_rebuild SET value = 30
WHERE name = 'S1' AND time = TO_DATE('2026-01-01 00:01:00');
EXEC ROLLUP_REBUILD(ch6_rebuild, 'S1',
TO_DATE('2026-01-01 00:00:30'),
TO_DATE('2026-01-01 00:01:00'));
```
### 3. 元データ・通常・Customの結果比較
```sql
SELECT DATE_TRUNC('minute', time) AS bucket, SUM(value), COUNT(value), AVG(value)
FROM ch6_rebuild WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
SELECT rollup('min', 1, time) AS bucket, SUM(value), COUNT(value), AVG(value)
FROM ch6_rebuild WHERE name = 'S1'
GROUP BY bucket ORDER BY bucket;
SELECT time, SUM(sum_value), SUM(cnt), SUM(sum_value) / SUM(cnt)
FROM ch6_rebuild_dst WHERE name = 'S1'
GROUP BY time ORDER BY time;
SHOW ROLLUPGAP;
```
3つの結果は、00:00が合計21・件数2・平均10.5、00:01が合計34・件数2・平均17です。
終了時刻より後の00:01:30の値4も、同じバケットを再計算するときに含まれる必要があります。
## 運用への影響と障害復旧
関連ジョブは処理位置に追いついてから、停止・再計算・再開始されます。
元データを安定して検索するための内部処理も実行するため、「再構築中も通常処理がそのまま継続する」とは説明しません。
ユーザークエリと収集に許容できる遅延・停止時間を、先に検証環境で測定してください。
複数の段階が1つのアトミックなトランザクションとして取り消されるとは考えないでください。
失敗時の状態復旧はベストエフォートで実行されるため、実データとV$ROLLUPを確認します。
元の停止状態をそのまま復元する保証もありません。
再実行前に、サポート対象、元データの残存、再集計範囲を確認してください。
存在しないタグは、有効な再構築対象が準備された状況ではno-opになる場合があります。
成功応答だけで意図したタグを処理したと判断せず、実際の結果を比較してください。
元データが削除されている場合、元の統計は復元できません。
## クリーンアップ
```sql
DROP ROLLUP ch6_rebuild_custom;
DROP TABLE ch6_rebuild_dst;
DROP TABLE ch6_rebuild CASCADE;
```
Customの出力先は別途削除します。通常の定義自体を変更する必要がある場合や、このプロシージャの範囲外の場合は、
サポートされる新しい定義とデータ移行の手順を用意してください。
内部保存テーブルを任意に削除するSQLを、代替手順として提示しないでください。
正確な引数は[REBUILDリファレンス](../../reference/sql/syntax/rollup-rebuild-syntax/)を参照してください。
---
title: "6.11 ROLLUPのパフォーマンスチューニング"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/performance-tuning-rollup/
language: ja
kind: page
---
# 6.11 ROLLUPのパフォーマンスチューニング
## 同じ結果を確認してからコストを比較
ROLLUPの効果は、読み取る生データの行数を減らすことにあります。
まずタグ、時間区間、NULL処理、集計基準が同じ結果になることを確認し、実行時間・CPU・I/O・メモリを比較します。
小さな例の実行時間は、本番性能を保証しません。
## 比較実習
```sql
CREATE TAG TABLE ch6_perf (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE,
quality INTEGER
);
CREATE ROLLUP ch6_perf_ru ON ch6_perf(value) INTERVAL 1 MIN;
INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10.0, 1);
INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:00:30', 'YYYY-MM-DD HH24:MI:SS'), 20.0, 1);
INSERT INTO ch6_perf VALUES ('TEMP_01', TO_DATE('2026-01-01 00:01:00', 'YYYY-MM-DD HH24:MI:SS'), 30.0, 1);
INSERT INTO ch6_perf VALUES ('TEMP_02', TO_DATE('2026-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), 100.0, 1);
EXEC TABLE_FLUSH(ch6_perf);
ALTER ROLLUP ch6_perf_ru FORCE;
SELECT DATE_TRUNC('minute', time) AS bucket,
SUM(value), COUNT(value), AVG(value), MIN(value), MAX(value)
FROM ch6_perf
WHERE name = 'TEMP_01'
AND time >= TO_DATE('2026-01-01 00:00:00')
AND time < TO_DATE('2026-01-01 00:02:00')
GROUP BY bucket ORDER BY bucket;
SELECT rollup('min', 1, time) AS bucket,
SUM(value), COUNT(value), AVG(value), MIN(value), MAX(value)
FROM ch6_perf
WHERE name = 'TEMP_01'
AND time >= TO_DATE('2026-01-01 00:00:00')
AND time < TO_DATE('2026-01-01 00:02:00')
GROUP BY bucket ORDER BY bucket;
EXPLAIN SELECT rollup('min', 1, time) AS bucket, AVG(value)
FROM ch6_perf WHERE name = 'TEMP_01'
GROUP BY bucket;
```
両方の結果は、00:00が合計30・件数2・平均15・最小値10・最大値20、
00:01が合計30・件数1・平均30・最小値30・最大値30です。
元データを読むDATE_TRUNCクエリの実行計画も、同じ方法で確認します。
## 運用負荷の測定
| 項目 | 併せて記録する条件 |
|---|---|
| 入力スループット | タグ数・入力レート・行幅・同時入力クライアント数 |
| クエリ遅延 | タグ範囲・バケット・同時クエリ数・コールドまたはウォームキャッシュ |
| 集計遅延 | 階層別のgap・ジョブ状態・処理時間 |
| 保存容量 | 元データ・集計・インデックス・圧縮・レプリカ |
| 変更の影響 | WAKEUP周期と階層の変更前後の入力・検索コスト |
WAKEUPを短くすると、同じバケットに部分集計がより頻繁に作成される場合があります。
集計バケットを小さくすると、保存量と再集計量が増えます。両方の間隔を同じチューニング項目として扱わないでください。
単独実行だけでなく、入力と検索が同時に進む状況も測定します。
## 階層サイズの意味
1つのタグが30日間のすべての区間にデータを持つと仮定した場合の、論理バケット数です。
| 検索区間 | バケット数 |
|---|---:|
| 1秒 | 2,592,000 |
| 1分 | 43,200 |
| 1時間 | 720 |
| 1日 | 30 |
これは物理的な保存行数ではありません。
複数の部分集計、空の区間、NULL、条件フィルターを含む実際の保存量は、サンプルのロードで測定します。
最も粗い候補が常に正しい結果を作るわけでもないため、必要な解像度・origin・候補選択の制約を併せて確認してください。
日単位の結果には、適用可能なHOUR/MIN/SEC集計を再集計します。
24 HOUR ROLLUPを`rollup('day', 1, ...)`の代替保存階層として推奨しません。
[クエリ候補の規則](../query-syntax-rollup/)と実際のEXPLAINを基準にしてください。
## 遅延と不一致の区別
gap=0は処理位置に追いついたことを表し、元データの補正が反映済みであることを意味しません。
性能比較の前に、集計の進行状況と過去の訂正状態を区別し、定義とフィルターが一致するか確認してください。
適用可能なROLLUPがない`rollup()`クエリを、元データの性能測定に使用しないでください。
## クリーンアップ
```sql
DROP ROLLUP ch6_perf_ru;
DROP TABLE ch6_perf;
```
[制御と状態](../ingestion-control-rollup/)、[階層設計](../target-tag-table-design/)、
[トラブルシューティング](../../troubleshooting/rollup/)を参照して次の調整を選択してください。
---
title: "6.12 ROLLUPの活用シナリオ"
url: https://docs.machbase.com/ja/dbms/tag-rollup-usage/patterns-scenarios/
language: ja
kind: page
---
# 6.12 ROLLUPの活用シナリオ
## センサー別の元データと区間統計
2つのセンサーが同時刻に測定しても、単位が異なる場合は平均を混在させません。
次は、現在の単位をメタデータで管理し、タグ別の集計を検索する独立した実習です。
### 1. 作成と入力
```sql
CREATE TAG TABLE ch6_scenario (
name VARCHAR(32) PRIMARY KEY, time DATETIME BASETIME, value DOUBLE
) METADATA (unit VARCHAR(16));
INSERT INTO ch6_scenario METADATA VALUES ('TEMP_01', 'celsius');
INSERT INTO ch6_scenario METADATA VALUES ('PRESS_01', 'bar');
INSERT INTO ch6_scenario VALUES ('TEMP_01', TO_DATE('2026-01-01 10:00:00'), 20);
INSERT INTO ch6_scenario VALUES ('TEMP_01', TO_DATE('2026-01-01 10:00:30'), 22);
INSERT INTO ch6_scenario VALUES ('PRESS_01', TO_DATE('2026-01-01 10:00:00'), 1.02);
CREATE ROLLUP ch6_scenario_ru ON ch6_scenario(value) INTERVAL 1 MIN;
EXEC TABLE_FLUSH(ch6_scenario);
ALTER ROLLUP ch6_scenario_ru FORCE;
```
元データの入力後にROLLUPを作成しても、残っているデータを初期集計します。
作成の完了だけで、初期集計も完了したと判断しないでください。
### 2. 結果の確認
```sql
SELECT name, unit FROM ch6_scenario METADATA ORDER BY name;
SELECT name, DATE_TRUNC('minute', time) AS bucket, COUNT(value), AVG(value)
FROM ch6_scenario GROUP BY name, bucket ORDER BY name, bucket;
SELECT name, rollup('min', 1, time) AS bucket, COUNT(value), AVG(value)
FROM ch6_scenario GROUP BY name, bucket ORDER BY name, bucket;
SHOW ROLLUPGAP;
```
TEMP_01は2件・平均21°C、PRESS_01は1件・平均1.02barです。
メタデータ検索で得られるのは現在の単位であり、過去の単位変更履歴は自動的に保持されません。
### 3. 個別の観測値の確認
固定時刻のデータを入力したため、同じ固定範囲を検索します。
このデータに現在時刻を基準にした「直近5分」の条件を適用すると、実行日に応じて結果が空になります。
```sql
SELECT name, time, value FROM ch6_scenario
WHERE name = 'TEMP_01'
AND time >= TO_DATE('2026-01-01 10:00:00')
AND time < TO_DATE('2026-01-01 10:01:00')
ORDER BY time;
```
元の2つの値は20と22です。統計上の平均21から、個々の観測値や発生順序を復元することはできません。
### 4. クリーンアップ
```sql
DROP ROLLUP ch6_scenario_ru;
DROP TABLE ch6_scenario;
```
## 業務別の適用
| 要求 | 確認する設計 |
|---|---|
| 正常品質の統計 | 条件フィルターと候補ヒントを固定して元データと比較 |
| OHLC | 拡張ROLLUPのFIRST/LAST、またはCustomの補助時刻による再集計 |
| 複数センサーの比較 | タグ別の単位と同じバケット・検索範囲を使用 |
| 累積メーターの消費量 | 境界の差、初期化・交換・欠損の規則。サンプル平均と区別 |
| 稼働率 | サンプル比率と時間比率の区別、欠測区間のポリシー |
| 最新の元データと長期集計の結合 | 集計完了を確認した基準点で区間が重複しないよう分割 |
元データとROLLUPの結果をUNION ALLで結合する場合は、境界の重複・欠落とサンプル数の違いを確認してください。
「直近2分は常に未集計」などの固定遅延を保証として使用しないでください。
部分結果を再結合して平均を求める場合は、合計と有効件数を渡します。
機能別の完結した実習は、[条件付き](../conditional-rollup/)、[拡張](../extension-rollup/)、
[JSON](../json-summarized-rollup/)、[Custom](../custom-rollup/)にあります。
問題が発生したら、[診断手順](../../troubleshooting/rollup/)に従って状態と意味を先に確認してください。
---
title: "7. LOGテーブルの活用"
url: https://docs.machbase.com/ja/dbms/log-table-usage/
language: ja
kind: section
---
# 7. LOGテーブルの活用
ログを保存することと、必要なログを探し出すことは別の作業です。
障害分析では、「この時刻は発生時刻か収集時刻か」「メッセージ内の単語がなぜ検索されないか」など、
入力時には考えていなかった問題に直面します。
この章では、LOGテーブルの選択・設計から入力、検索、保持管理までを一連の流れで説明します。
コマンドの実行方法に加え、結果の確認基準も学びます。
LOGは元のイベントを継続的に追加するモデルであり、保存済みの行を繰り返し更新する業務テーブルとは使い方が異なります。
## この章の構成
初めての場合は、概要とスキーマを読んでから、作成・入力・検索の順に進めてください。
時間条件を確認するなら7.10、メッセージ検索が目的なら7.11から読むこともできます。
| 節 | 学習内容 |
|---|---|
| [7.1 概要と選択基準](./overview-use-criteria/) | LOGと他のテーブルの用途の区別 |
| [7.2 テーブル構造とスキーマ](./table-structure-schema/) | 発生時刻・検索フィールド・原文の分離 |
| [7.3 作成、変更、削除](./create-alter-drop/) | 既存データを確認しながらスキーマを変更 |
| [7.4 データ入力](./data-input-mutation/) | INSERT・Append・ファイルロードの選択 |
| [7.5 クエリと分析](./query-analysis/) | 時間範囲検索とマスターデータの結合 |
| [7.6 インデックスとパフォーマンス](./index-performance/) | インデックスの選択と実行計画の確認 |
| [7.7 運用とデータライフサイクル](./operations-lifecycle/) | 削除境界の確認と保持ポリシーの適用 |
| [7.8 制約、エラー、トラブルシューティング](./constraints-errors-troubleshooting/) | 症状から原因と対処を特定 |
| [7.9 活用パターンとシナリオ](./patterns-scenarios/) | アプリケーションログの入力・検索・集計 |
| [7.10 _arrival_timeの時間モデル](./arrival-time-model/) | 自動時刻・明示時刻・時刻逆転入力の区別 |
| [7.11 テキスト検索とKEYWORDインデックス](./text-search-keyword-index/) | 検索方法による結果の違い |
| [7.12 ネットワーク型のクエリ](./regex-network-query/) | IPV4・IPV6のアドレスと範囲の検索 |
## 実習環境
この章の例はDBMS 8.7の文書に基づき、特に断りのないSQL実習はStandard Editionの検証環境を対象とします。
テーブルとインデックスを作成できるアカウントを使用してください。
Cluster環境では、[Editionごとの違い](/ja/dbms/reference/support-scope-constraints/edition/)と該当する運用手順も確認する必要があります。
実習用オブジェクトは`ch7_`で始まります。各節で必要なテーブルを作成するため、他の節を実行せずに進められます。
同じ節を再実行する場合は、最後のクリーンアップSQLまで実行したことを確認してください。
意図的に失敗するSQLは通常の実習と分離しています。
注意: `DELETE`、`TRUNCATE`、`DROP`はデータを削除するコマンドです。
例の名前を本番テーブル名に置き換えて実行しないでください。
実習結果が異なる場合は、実行したSQLと実際の結果を比較してください。
どの段階から差が生じたかを確認すると、原因を絞り込みやすくなります。
---
title: "7.1 概要と選択基準"
url: https://docs.machbase.com/ja/dbms/log-table-usage/overview-use-criteria/
language: ja
kind: page
---
# 7.1 概要と選択基準
時刻を持つデータをすべて同じテーブルに保存する必要はありません。
定期的に測定した温度と「デバイスが再接続した」というイベントでは、分析方法が異なります。
LOGを選ぶときは、時間カラムの有無より、1行が何を表すかを先に考えてください。
## LOGテーブルの特性
アプリケーションエラー、セキュリティ機器の遮断記録、処理の開始・終了履歴など、イベントを1件ずつ追加するデータにLOGが適しています。
ユーザーカラムに加えて`_arrival_time`が自動的に作成され、時間範囲条件とメッセージ検索を併用できます。
次の例で、イベント発生時刻と入力時刻の違いを確認します。
```sql
CREATE LOG TABLE ch7_overview (
event_time DATETIME,
device VARCHAR(32),
message VARCHAR(128)
);
INSERT INTO ch7_overview VALUES (
TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'),
'DEV-01', 'connection restored'
);
SELECT _arrival_time, event_time, device, message FROM ch7_overview;
DROP TABLE ch7_overview;
```
1行が返されます。`event_time`は例に指定した固定時刻、`_arrival_time`は今回の入力で自動的に決まった時刻です。
したがって、実行日が変わっても`event_time`は変わりません。
明示的な入力と補正規則については[時間モデル](../arrival-time-model/)で説明します。
## 選択基準
「過去1時間のエラー」「このIPアドレスからのリクエスト」「timeoutを含むメッセージ」を頻繁に検索し、
保存済みの行を更新する必要がない場合は、まずLOGを検討してください。
継続入力にはAppend API、初期データやファイル群にはロードツールを使用できます。
入力後に更新できないことだけで、監査データの改ざん防止が保証されるわけではありません。
削除権限、アクセス制御、保持ポリシー、バックアップは別途設計する必要があります。
再送には注意が必要です。同じイベントを再送すると、別の行として保存される場合があります。
LOGにはPRIMARY KEY・UNIQUE制約がないため、自動的な重複排除は期待できません。
元のイベントIDを保持し、収集段階で再試行と重複処理のポリシーを定めてください。
## 他のテーブルとの比較
| 主な用途 | 最初に検討するテーブル | 判断基準 |
|---|---|---|
| センサー名ごとの測定値と時系列集計 | TAG | 名前・時間軸による検索とROLLUPが中心 |
| 機器名・設置場所などの現在のマスターデータ | LOOKUP | 小規模な参照データを検索・更新 |
| 注文状態の変更・行削除・トランザクション処理 | TRANSACTION | 行を更新し、取引単位で処理 |
| 再起動後に失われてもよいメモリ上の状態 | VOLATILE | 永続保存する元のログから分離 |
LOGは一般的な`UPDATE`と任意条件の`DELETE WHERE`をサポートしていません。
訂正イベントを追加する設計は可能ですが、元のIDと訂正理由を保存し、
検索時にどの訂正を反映するかをアプリケーションで決める必要があります。
更新が日常的に発生する業務では、最初から別のテーブルを使うほうが明確です。
## 設計基準
分析に必要なのが発生時刻か収集時刻かを、まず区別します。
続いて、デバイス・重要度・IPなど、頻繁に使用する条件を決めてください。
これらの値は毎回原文から切り出すより、別カラムに格納するとクエリを理解・管理しやすくなります。
保持期間もこの段階で決めてください。入力方法だけを用意して削除を後回しにすると、ディスク使用量が増え続けます。
次の[スキーマ設計](../table-structure-schema/)では、これらの観点を実際のカラムに反映します。
選択に迷う場合は、代表的なイベント数件と頻繁に使用するクエリを並べて比較してください。
---
title: "7.2 テーブル構造とスキーマ"
url: https://docs.machbase.com/ja/dbms/log-table-usage/table-structure-schema/
language: ja
kind: page
---
# 7.2 テーブル構造とスキーマ
メッセージ全体を1つのカラムに格納すれば、収集をすぐに開始できます。
しかし、後から機器別のエラー件数を求めるために毎回原文を解析すると、クエリが複雑になります。
この節では、原文を保持しつつ、繰り返し検索・集計する値を別カラムに取り出す方法を説明します。
## カラム構成
次は、セキュリティイベントを1件保存して確認する独立した実習です。
```sql
CREATE LOG TABLE ch7_schema (
event_time DATETIME,
event_id VARCHAR(64),
device VARCHAR(32),
severity SHORT,
src_ip IPV4,
dst_port INTEGER,
message TEXT
);
INSERT INTO ch7_schema VALUES (
TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'),
'evt-0001', 'FW-01', 3, '192.0.2.10', 65535,
'connection blocked by policy'
);
SELECT event_id, device, severity, src_ip, dst_port, message
FROM ch7_schema;
```
`evt-0001`の1行とポート`65535`が返されます。
ここでの`event_id`は追跡用の値であり、重複入力を防ぐキー制約ではありません。
`event_time`には、入力元が記録した発生時刻を保存します。
自動カラムの`_arrival_time`をDDLで再宣言しないでください。
ネットワーク遅延や一括移行があると、2つの時刻が異なるのは自然なことです。
## データ型の選択
| 値 | 選択する型 | 確認事項 |
|---|---|---|
| デバイス名・短いコード・イベントID | `VARCHAR(n)` | LOGの宣言範囲は1~32,767バイトであり、文字数ではない |
| 長い原文メッセージ | `TEXT` | 最大64MiB。原文自体のソート・グループ化は未サポート |
| エラーの重要度・小さなコード | `SHORT`または`INTEGER` | 各コードの意味を収集側と検索側で統一 |
| ポート | `INTEGER` | `USHORT`の65535はNULLの予約値のため、ポート全範囲には不適切 |
| 累積バイト数 | `LONG` | 想定最大値とNULLの予約値を確認 |
| アドレス | `IPV4`または`IPV6` | アドレス形式と元の文字列の保存要否を区別 |
LOGでは、VARCHARとTEXTの両方でKEYWORDインデックスによる単語検索が可能です。
全文検索を行うという理由だけで、短いコードまでTEXTにする必要はありません。
文字列長には注意が必要です。`VARCHAR(100)`は韓国語100文字を意味しません。
UTF-8サンプルのバイト数を確認し、長さを超える値を実際の入力方法で送ってください。
長さ超過が切り詰めとエラーのどちらになるかは、使用するSDKやロードツールも含めて確認する必要があります。
## ソート・集計用カラム
上のスキーマでは、`device`・`severity`を検索条件と集計基準に使用し、
`message`を原文の読み取りや単語検索に使用します。
`ORDER BY message`や`GROUP BY message`のようにTEXT自体を対象にするとエラーになります。
メッセージ全体をソートするより、デバイス、エラーコード、発生時刻から実際に必要な基準を決めてください。
KEYWORDインデックスは、形態素解析器や検索スコアに基づく検索エンジンと同じものではありません。
単語検索と原文の部分文字列検索の違いは、[テキスト検索](../text-search-keyword-index/)で確認できます。
## スキーマ変更と入力マッピング
LOGはカラムの追加・削除・名前変更と、限定的な属性変更をサポートしています。
ただし、保存した行の値をUPDATEで変更できるわけではありません。
特にカラム順に送信するAppenderとCSVマッピングはDDL変更の影響を受けるため、変更時刻と入力プログラムの展開を併せて計画してください。
実習テーブルを削除してから、[カラム変更の実習](../create-alter-drop/)に進みます。
```sql
DROP TABLE ch7_schema;
```
どの値をカラムに取り出すべきか迷う場合は、実際に答える必要がある問いを書き出してください。
その問いをSQLで表現すると、必要なカラムも明確になります。
---
title: "7.3 作成、変更、削除"
url: https://docs.machbase.com/ja/dbms/log-table-usage/create-alter-drop/
language: ja
kind: page
---
# 7.3 作成、変更、削除
カラム追加のSQLは短くても、運用では既存行に表示される値と、既存の入力プログラムが引き続き動作するかを確認する必要があります。
この節では、データがある状態でスキーマを変更し、その結果を確認します。
## LOGテーブルの作成
テーブル型を省略した`CREATE TABLE`はTRANSACTIONテーブルを作成します。
この実習では`CREATE LOG TABLE`を使用してください。
```sql
CREATE LOG TABLE ch7_ddl (
event_id INTEGER,
category VARCHAR(32),
severity SHORT,
message VARCHAR(128)
);
INSERT INTO ch7_ddl VALUES (1, 'network', 3, 'connection timeout');
```
自動カラム`_arrival_time`はDDLに再宣言しません。
実際の発生時刻が必要なら、別のDATETIMEカラムを用意してください。
LOGではPRIMARY KEY・UNIQUE制約をサポートしていません。
## カラム追加とデフォルト値
```sql
ALTER TABLE ch7_ddl ADD COLUMN (host_name VARCHAR(64));
ALTER TABLE ch7_ddl ADD COLUMN (source_kind VARCHAR(16) DEFAULT 'agent');
ALTER TABLE ch7_ddl ADD COLUMN (channels INT32[3] DEFAULT [1, NULL, 3]);
SELECT event_id, host_name, source_kind, channels
FROM ch7_ddl
ORDER BY event_id;
```
既存の行1では、`host_name`がNULL、`source_kind`が`agent`、
`channels`が`[1, NULL, 3]`として返されます。
DEFAULTを持つカラムと持たないカラムの違いを確認してください。
ARRAYのDEFAULTは、要素数が宣言した長さと一致する必要があります。
続いて、カラム名を変更し、文字列長を拡張します。
```sql
ALTER TABLE ch7_ddl RENAME COLUMN category TO event_category;
ALTER TABLE ch7_ddl MODIFY COLUMN (message VARCHAR(4096));
ALTER TABLE ch7_ddl MODIFY COLUMN severity SET MINMAX_CACHE_SIZE = 1048576;
SELECT event_id, event_category, severity, message FROM ch7_ddl;
```
既存行の値は保持されます。名前の変更後は、検索SQLでも`event_category`を使用する必要があります。
MINMAXの例は数値カラムに1MiBを指定したもので、すべてのテーブルに推奨する値ではありません。
型変更には注意が必要です。VARCHARの長さの拡張は、TEXTをVARCHARに変換する操作ではありません。
`MINMAX_CACHE_SIZE`もVARCHAR・TEXTなどの可変長カラムには設定できません。
## NOT NULLと既存データ
現在の`event_category`には値があるため、次の変更が可能です。
```sql
ALTER TABLE ch7_ddl MODIFY COLUMN event_category NOT NULL;
ALTER TABLE ch7_ddl MODIFY COLUMN event_category NULL;
```
オプションなしの`NOT NULL`は既存行を検査します。
NULLを含む`host_name`には適用できません。次のSQLは、失敗を確認する場合にのみ個別に実行してください。
```sql
-- 意図的に失敗: 既存行のhost_nameはNULLです。
ALTER TABLE ch7_ddl MODIFY COLUMN host_name NOT NULL;
```
`NOT NULL NOCHECK`は既存のNULL検査を省略します。
既存のNULLを埋めたり、過去のデータも条件を満たすと保証したりするオプションではありません。
この実習の通常の手順では使用しません。
## インデックスとカラムの削除
```sql
CREATE INDEX ch7_ddl_host_idx ON ch7_ddl(host_name) INDEX_TYPE LSM;
DROP INDEX ch7_ddl_host_idx;
ALTER TABLE ch7_ddl DROP COLUMN (host_name);
ALTER TABLE ch7_ddl DROP COLUMN (source_kind);
ALTER TABLE ch7_ddl DROP COLUMN (channels);
SELECT event_id, event_category, severity, message FROM ch7_ddl;
```
インデックスが参照するカラムを削除するには、先にインデックスを削除してください。
内部カラム`_ARRIVAL_TIME`・`_RID`は削除・名前変更・属性変更の対象にできず、
ユーザーカラムは少なくとも1つ残す必要があります。
VARCHARの長さは既存より大きくすることだけが可能で、最大32,767バイトの範囲内にする必要があります。
## データの削除とテーブルの削除
注意: 次のコマンドは実習データを削除します。
LOGデータはTRANSACTIONテーブルの`ROLLBACK`では元に戻せません。
```sql
TRUNCATE TABLE ch7_ddl;
SELECT COUNT(*) AS remaining_rows FROM ch7_ddl;
DROP TABLE ch7_ddl;
```
TRUNCATE後の件数は0になり、定義は残ります。最後のDROPは定義も削除します。
古いデータの一部だけを削除するには、[保持期間に基づく削除](../operations-lifecycle/)を使用してください。
## DDL運用上の注意事項
変更前に入力処理とDDLの実行時刻を調整し、変更後にSQL・Appender・ファイルマッピングの
カラム名・順序・型を確認します。リソース使用中エラーが発生したら、繰り返し実行する前に、
対象テーブルを使用している処理を確認してください。
どの変更で問題が起きたか不明な場合は、変更前のDDLと失敗したSQLを用意してください。
この2つがあると、原因をより早く絞り込めます。
---
title: "7.4 データ入力"
url: https://docs.machbase.com/ja/dbms/log-table-usage/data-input-mutation/
language: ja
kind: page
---
# 7.4 データ入力
1、2行の入力に成功しても、収集の準備が完了したとは限りません。
継続的な収集では、送信バッファ、一部の行の失敗、切断後の再送も考慮する必要があります。
まずSQLでカラムと時刻を確認し、実際のスループットに適した入力方法を選択してください。
## SQL INSERT
```sql
CREATE LOG TABLE ch7_input (
event_time DATETIME,
event_id VARCHAR(32),
device VARCHAR(32),
message VARCHAR(128)
);
INSERT INTO ch7_input(event_time, event_id, device, message)
VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'),
'evt-001', 'DEV-01', 'connection timeout');
SELECT _arrival_time, event_time, event_id, device, message
FROM ch7_input;
```
1行が返され、`event_time`は固定の発生時刻です。
`_arrival_time`を省略したため、入力処理でサーバー時刻が使用されます。
デフォルト設定では時刻逆転時に補正が発生し得るため、常に実際の受信時刻と正確に一致するとは限りません。
詳細な規則は[時間モデル](../arrival-time-model/)を参照してください。
同じイベントを再度入力した場合の動作も確認します。
```sql
INSERT INTO ch7_input(event_time, event_id, device, message)
VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'),
'evt-001', 'DEV-01', 'connection timeout');
SELECT event_id, COUNT(*) AS received_rows
FROM ch7_input
GROUP BY event_id;
DROP TABLE ch7_input;
```
`evt-001`の件数は2です。名前が同じでもLOGは重複を除去しません。
収集アプリケーションの「送信完了」と、元のイベントを「一度だけ保存すること」は別の問題です。
## 入力方法の選択
| 状況 | 最初に検討する方法 | 併せて確認する項目 |
|---|---|---|
| 少量入力・機能確認 | SQL INSERT | カラムリスト、型、日付書式 |
| アプリケーションからの継続的な大量入力 | SDK Append | バッファ送信、行単位の失敗、再接続ポリシー |
| クライアントが読み込むCSV | csvimport・machloader | カラムマッピング、失敗行ファイル |
| サーバーから読み込めるロード用ファイル | LOAD DATA INFILE | サーバー上のパスとファイルアクセス権限 |
SQL INSERTには文ごとの処理コストがあります。継続的な大量入力には、複数行をまとめて送信するAppend APIを検討してください。
言語別の実行コードは[開発とアプリケーション連携](/ja/dbms/development-tools-integration/)から選択できます。
## Appendの送信とエラー処理
Appenderに行を渡した時点では、データがクライアントバッファに残っている場合があります。
使用するSDKのflush・closeの動作を確認し、正常終了時だけでなく例外発生時にも、残りのバッファと接続を処理してください。
呼び出しが成功しても、すべての行が保存されたとは限りません。
SDKによって、戻り値、エラーコールバック、終了時の成功・失敗件数など、結果の確認方法が異なります。
長さ超過、NULL、日付変換エラーを意図的に含めた小さなバッチで、先に確認することを推奨します。
応答を受け取る前に接続が切れる場合は特に注意が必要です。
保存済みのバッチを再送する可能性があるため、元のイベントIDと処理位置を記録してください。
LOGのINSERT・Appendは、TRANSACTIONテーブルのトランザクションのROLLBACK対象でもありません。
## ファイルロードとマッピング
韓国語・空文字列・NULL・長いメッセージ・異なるタイムゾーンを含むサンプルを用意してください。
元のフィールド数と対象カラムの順序が一致することを確認してから、ファイル全体を処理します。
同じエラーを再分析できるよう、失敗行ファイルとログも保存してください。
コマンド全体は[データ入力・ロード・エクスポート](/ja/dbms/development-tools-integration/data-input-load-export/)を参照してください。
過去データの移行で`_arrival_time`を保持するには、ソート順と移行先の既存データも確認する必要があります。
通常の収集で過去の発生時刻を扱う場合は、別の`event_time`に保存するほうが安全です。
問題が起きたら、バッチ全体より先に、失敗した元の1行を確認してください。
フィールド値、対象の型、使用した入力APIを合わせて確認すると原因を特定しやすくなります。
---
title: "7.5 クエリと分析"
url: https://docs.machbase.com/ja/dbms/log-table-usage/query-analysis/
language: ja
kind: page
---
# 7.5 クエリと分析
時間範囲を少し変えるだけでも検索件数は変わります。
特に日単位の集計では、終了時刻を両方の区間に含めると境界上の行が重複します。
この節では、固定時刻のデータで範囲と結果の順序を確認し、マスターデータを結合します。
## 実習データの準備
```sql
CREATE LOG TABLE ch7_query (
event_id INTEGER,
device VARCHAR(32),
value DOUBLE
);
INSERT INTO ch7_query(_arrival_time, event_id, device, value)
VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 'DEV-01', 10);
INSERT INTO ch7_query(_arrival_time, event_id, device, value)
VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 2, 'DEV-01', 20);
INSERT INTO ch7_query(_arrival_time, event_id, device, value)
VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'DEV-02', 30);
INSERT INTO ch7_query(_arrival_time, event_id, device, value)
VALUES (TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS'), 4, 'DEV-02', 40);
SELECT _arrival_time, event_id, device, value
FROM ch7_query
ORDER BY _arrival_time, event_id;
```
結果はイベント1・2・3・4の順です。イベント2と3のように同時刻の行もあるため、
順序を固定するには、時刻に加えてイベント番号もソート条件に指定します。
この番号は例の中で明示的に管理する値で、LOGの自動的な一意キーではありません。
## 連続区間と時間境界
```sql
SELECT event_id, value
FROM ch7_query
WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND _arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id;
```
イベント1・2・3が選択されます。次の区間を12:00から始めると、イベント4はその区間でのみ集計されます。
`BETWEEN`は両端を含むため、このような連続区間とは意味が異なります。
ユーザー定義の`event_time`を基準に分析する場合も、同じWHEREパターンを使用できます。
## DURATIONによる検索
```sql
SELECT event_id FROM ch7_query
DURATION 1 HOUR BEFORE TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id;
SELECT event_id FROM ch7_query
DURATION 1 HOUR AFTER TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id;
SELECT event_id FROM ch7_query
DURATION FROM TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
TO TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id;
```
| クエリ | 時間範囲 | 選択されるevent_id |
|---|---|---|
| 12:00以前の1時間 | 11:00~12:00、両端を含む | 2, 3, 4 |
| 10:00以後の1時間 | 10:00~11:00、両端を含む | 1, 2, 3 |
| 10:00から12:00まで | 両端を含む | 1, 2, 3, 4 |
`DURATION 1 HOUR`のように基準時刻を省略すると、現在時刻を基準にします。
そのため、過去の固定時刻を使う実習にそのまま適用すると、結果が得られない場合があります。
構文上の位置はWHEREの後、GROUP BY・ORDER BYの前です。
DURATIONがすべての時間カラムに適用される条件だと誤解しないでください。
DURATIONはLOG専用で、`_arrival_time`を使用します。
TAGの時間カラムやユーザー定義DATETIMEの条件はWHEREで指定してください。
詳細な構文は[相対時間・DURATIONリファレンス](/ja/dbms/reference/sql/relative-time/#log-duration)を参照してください。
## スキャン方向とソート
DURATIONのBEFOREは新しい側から、AFTERは古い側から読み取る方向を指定します。
FROM … TOは、2つの時刻の順序によって方向が変わります。
次の例では、逆順の範囲と同時刻の境界を確認します。
```sql
SELECT event_id FROM ch7_query
DURATION FROM TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
TO TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id DESC;
SELECT event_id FROM ch7_query
DURATION FROM TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS')
TO TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY event_id;
```
最初の結果はイベント4・3・2・1、同じ時刻を指定した2番目の結果はイベント2・3です。
ここではスキャン方向とは別にORDER BYを明示し、出力順序を固定しています。
集計や結合を含む最終結果の順序が必要な場合は、ORDER BYを明示してください。
特にLIMITだけを指定して、どの行が返されるかを推測しないでください。
グローバル設定`TABLE_SCAN_DIRECTION`は他のクエリにも影響する場合があります。
画面の出力順序を変えるために、先にサーバー設定を変更しないでください。
[クエリチューニング](/ja/dbms/performance-tuning/performance-query-tuning/)で実行計画を確認してから、必要なアクセス経路を調整してください。
## LOOKUPとの結合
```sql
CREATE LOOKUP TABLE ch7_query_device (
device VARCHAR(32) PRIMARY KEY,
label VARCHAR(64)
);
INSERT INTO ch7_query_device VALUES ('DEV-01', 'Boiler');
INSERT INTO ch7_query_device VALUES ('DEV-02', 'Pump');
SELECT q.event_id, d.label, q.value
FROM ch7_query q
JOIN ch7_query_device d ON q.device = d.device
WHERE q._arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND q._arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
ORDER BY q.event_id;
```
結果は`(1, Boiler, 10)`、`(2, Boiler, 20)`、`(3, Pump, 30)`です。
LOGとLOOKUPを組み合わせるクエリのため、DURATIONの代わりにLOGカラムのWHERE範囲条件を使用します。
このINNER JOINでは、対応するマスターデータがないイベントは結果から除外される点も確認してください。
また、現在のLOOKUP値を結合しても、過去の機器説明が復元されるわけではありません。
履歴が必要なら、その時点の説明をイベントに保存するか、有効期間を持つ履歴を別途設計する必要があります。
```sql
DROP TABLE ch7_query_device;
DROP TABLE ch7_query;
```
検索件数が予想と異なる場合は、時間境界と結合前の件数を先に確認してください。
条件を1つずつ追加すると、どこで行が除外されるかを見つけやすくなります。
---
title: "7.6 インデックスとパフォーマンス"
url: https://docs.machbase.com/ja/dbms/log-table-usage/index-performance/
language: ja
kind: page
---
# 7.6 インデックスとパフォーマンス
インデックスを作成してもクエリが速くならない場合は、まずそのクエリがインデックスを使用できるか確認します。
インデックスは読み取りコストを減らす一方、入力・保存・バックグラウンド処理のコストを増やします。
カラムごとに作成するより、代表的な検索条件を決めるところから始めてください。
## インデックスの選択
| 検索条件 | 検討するインデックス | 確認事項 |
|---|---|---|
| 数値・DATETIMEなどの値と範囲 | LSM | 条件に適したサポート型と実際の実行計画 |
| VARCHAR・TEXTの単語・トークンパターン | KEYWORD | SEARCH・ESEARCHを使用し、LIKEとの結果の意味の違いを確認 |
| サポート型の繰り返し値の分析 | BITMAP | 値の分布とエンコーディング、入力・保存コスト |
LOGの`_arrival_time`範囲には、まず標準の時間アクセス経路を利用します。
同じ目的のインデックスを慣習的に追加する必要はありません。
サポート型と属性は[INDEX構文](/ja/dbms/reference/sql/syntax/index-syntax/)で確認してください。
一般的なRDBMSの複合インデックス設計をそのまま適用しないでください。
## インデックス作成前後の比較
```sql
CREATE LOG TABLE ch7_index (
event_id INTEGER,
event_time DATETIME,
severity SHORT,
message VARCHAR(256)
);
INSERT INTO ch7_index VALUES (
1, TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1, 'service started');
INSERT INTO ch7_index VALUES (
2, TO_DATE('2026-01-01 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'database timeout');
INSERT INTO ch7_index VALUES (
3, TO_DATE('2026-01-01 10:02:00', 'YYYY-MM-DD HH24:MI:SS'), 3, 'connection timeout');
EXPLAIN SELECT event_id FROM ch7_index WHERE severity = 3;
CREATE INDEX ch7_index_time ON ch7_index(event_time) INDEX_TYPE LSM;
CREATE INDEX ch7_index_message ON ch7_index(message) INDEX_TYPE KEYWORD;
CREATE INDEX ch7_index_severity ON ch7_index(severity)
INDEX_TYPE BITMAP BITMAP_ENCODE = RANGE;
EXEC TABLE_FLUSH(ch7_index);
EXEC INDEX_FLUSH(ch7_index);
EXPLAIN SELECT event_id FROM ch7_index WHERE severity = 3;
EXPLAIN SELECT event_id FROM ch7_index WHERE message SEARCH 'timeout';
SELECT event_id FROM ch7_index
WHERE message SEARCH 'timeout'
ORDER BY event_id;
SHOW INDEXES;
```
検索結果はイベント2と3です。実行計画で値条件とSEARCHが使用するアクセス経路を比較し、
SHOW INDEXESで作成された名前を確認してください。
この3行は動作を理解するためのサンプルであり、性能測定用のデータではありません。
## データとインデックスの反映
`TABLE_FLUSH`はテーブルデータを反映する操作、`INDEX_FLUSH`はインデックス構築が進むまで待機する操作です。
実習で作成前後の計画と時間を比較するときは、上記のように区別して使用してください。
インデックスが存在しても、入力データ全体のインデックスへの反映が完了したとは限りません。
構築の遅延は検索コストに影響し得ます。ただし、行を入力するたびに両方のコマンドを呼ぶと、バッチ入力の利点が減ります。
運用では入力レートとバックグラウンド処理速度を併せて監視し、必要な同期タイミングだけを決めてください。
インデックスへの反映が遅いことを理由に、同じデータを再入力しないよう注意してください。
重複を避けるため、再入力前に元データの検索件数とインデックス状態を個別に確認する必要があります。
## 性能測定の基準
作成前後で同じデータ量・条件値・同時入力負荷を使用してください。
1回の実行時間だけでなく、繰り返し検索の時間、入力スループット、インデックス容量、構築遅延を併せて記録します。
LIKE・REGEXPは元の文字列に対して条件を評価するため、先に時間範囲を制限すると検査対象を減らせます。
KEYWORDインデックスが存在しても、LIKEがSEARCHに変わるわけではありません。
```sql
DROP INDEX ch7_index_severity;
DROP INDEX ch7_index_message;
DROP INDEX ch7_index_time;
DROP TABLE ch7_index;
```
計画を読み取りにくい場合は、クエリとEXPLAINの結果を比較してください。
[インデックスチューニング](/ja/dbms/performance-tuning/index-tuning/)の診断手順が、次の確認箇所を決める参考になります。
---
title: "7.7 運用とデータライフサイクル"
url: https://docs.machbase.com/ja/dbms/log-table-usage/operations-lifecycle/
language: ja
kind: page
---
# 7.7 運用とデータライフサイクル
入力は正常でもディスク使用量が増え続ける場合は、削除基準を確認します。
LOGは業務条件で特定の行を選んで削除するモデルではなく、古い領域から削除するモデルです。
保持期間と、実際に削除される境界を併せて確認する必要があります。
## 削除方法の選択
| 目的 | コマンド | 基準 |
|---|---|---|
| 古いN行を削除 | OLDEST n ROWS | 古い入力行から削除 |
| 最新のN行のみ保持 | EXCEPT n ROWS | 残す行数 |
| 直近の期間のみ保持 | EXCEPT n DAYなど | サーバーの現在時刻から期間を引いた境界 |
| 固定時刻まで削除 | BEFORE datetime_expr | 指定した_arrival_timeの境界を含む |
| 全データを削除 | 条件なしのDELETEまたはTRUNCATE | 全行 |
| 定期的な期間管理 | Retention Policy | 保持期間と実行周期 |
注意: 削除を元に戻せると考えないでください。LOGデータはTRANSACTIONテーブルのROLLBACK対象ではありません。
本番環境では、バックアップと実際の対象範囲を確認してから実行してください。
## 削除方式の比較
コマンドを連続して実行すると、先の削除が次の結果に影響します。
ここでは、同じ3行を別々のテーブルにコピーして比較します。
```sql
CREATE LOG TABLE ch7_lifecycle (event_id INTEGER);
CREATE LOG TABLE ch7_oldest (event_id INTEGER);
CREATE LOG TABLE ch7_keep (event_id INTEGER);
CREATE LOG TABLE ch7_before (event_id INTEGER);
INSERT INTO ch7_lifecycle(_arrival_time, event_id)
VALUES (TO_DATE('2026-01-01', 'YYYY-MM-DD'), 1);
INSERT INTO ch7_lifecycle(_arrival_time, event_id)
VALUES (TO_DATE('2026-01-02', 'YYYY-MM-DD'), 2);
INSERT INTO ch7_lifecycle(_arrival_time, event_id)
VALUES (TO_DATE('2026-01-03', 'YYYY-MM-DD'), 3);
INSERT INTO ch7_oldest(_arrival_time, event_id)
SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time;
INSERT INTO ch7_keep(_arrival_time, event_id)
SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time;
INSERT INTO ch7_before(_arrival_time, event_id)
SELECT _arrival_time, event_id FROM ch7_lifecycle ORDER BY _arrival_time;
SELECT COUNT(*) AS delete_candidates FROM ch7_before
WHERE _arrival_time <= TO_DATE('2026-01-02', 'YYYY-MM-DD');
DELETE FROM ch7_oldest OLDEST 1 ROWS;
DELETE FROM ch7_keep EXCEPT 1 ROWS;
DELETE FROM ch7_before BEFORE TO_DATE('2026-01-02', 'YYYY-MM-DD');
SELECT event_id FROM ch7_oldest ORDER BY event_id;
SELECT event_id FROM ch7_keep ORDER BY event_id;
SELECT event_id FROM ch7_before ORDER BY event_id;
```
削除前に確認した件数は2です。各テーブルに残るイベントは次のとおりです。
| テーブル | 残るevent_id |
|---|---|
| ch7_oldest | 2, 3 |
| ch7_keep | 3 |
| ch7_before | 3 |
BEFOREという名前には注意が必要です。
現在のLOGの削除では、指定時刻と等しい行も含まれます。
`WHERE _arrival_time < 境界`で事前に件数を数えると削除対象と異なる場合があるため、上記のように`<=`で確認してください。
```sql
DELETE FROM ch7_lifecycle;
SELECT COUNT(*) AS remaining_rows FROM ch7_lifecycle;
DROP TABLE ch7_before;
DROP TABLE ch7_keep;
DROP TABLE ch7_oldest;
DROP TABLE ch7_lifecycle;
```
全件DELETE後の件数は0になり、テーブル定義は残ります。
## 相対期間による削除
```sql
CREATE LOG TABLE ch7_period (event_id INTEGER);
INSERT INTO ch7_period(_arrival_time, event_id) VALUES (SYSDATE - 2d, 1);
INSERT INTO ch7_period(_arrival_time, event_id) VALUES (SYSDATE, 2);
DELETE FROM ch7_period EXCEPT 1 DAY;
SELECT event_id FROM ch7_period ORDER BY event_id;
DROP TABLE ch7_period;
```
作成から検索まで続けて実行すると、イベント2だけが残ります。
基準は「最後に入力された行の時刻」ではなく、サーバーの現在時刻です。
入力が停止していても時間は進むことを、保持ポリシーにも反映してください。
## Retention Policy
次は保持期間1日・実行周期1分の検証用の例です。
本番環境の推奨値ではありません。ポリシーの作成とテーブルへの適用に必要な権限を持つアカウントを使用してください。
```sql
CREATE LOG TABLE ch7_retention (event_id INTEGER);
INSERT INTO ch7_retention(_arrival_time, event_id) VALUES (SYSDATE - 2d, 1);
INSERT INTO ch7_retention(_arrival_time, event_id) VALUES (SYSDATE, 2);
CREATE RETENTION ch7_policy DURATION 1 DAY INTERVAL 1 MIN;
ALTER TABLE ch7_retention ADD RETENTION ch7_policy;
SELECT * FROM M$RETENTION WHERE POLICY_NAME = 'CH7_POLICY';
SELECT TABLE_NAME, POLICY_NAME, STATE, LAST_DELETED_TIME
FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION';
SELECT event_id FROM ch7_retention ORDER BY event_id;
```
DURATIONは保持する期間、INTERVALは削除を実行する周期です。
適用直後は2行が表示される場合があります。1周期と処理時間が経過した後、次のクエリを再実行してイベント2だけが残るか確認してください。
LAST_DELETED_TIMEは削除の基準時刻であり、実時計における処理の完了時刻ではありません。
```sql
SELECT TABLE_NAME, STATE, LAST_DELETED_TIME
FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION';
SELECT event_id FROM ch7_retention ORDER BY event_id;
```
実習が終わったら、適用を解除してからポリシーとテーブルを削除します。
```sql
ALTER TABLE ch7_retention DROP RETENTION;
SELECT TABLE_NAME FROM V$RETENTION_JOB WHERE TABLE_NAME = 'CH7_RETENTION';
DROP RETENTION ch7_policy;
DROP TABLE ch7_retention;
```
解除後のジョブ検索結果は0件です。削除済みの行は復元されません。
1つのテーブルには1つのポリシーを適用します。使用中のポリシーは、先に解除してから削除してください。
運用基準の全体は[データ保持ポリシー](/ja/dbms/operations-configuration-recovery/policy-data-retention/)を参照してください。
## 削除前のバックアップ検証
バックアップファイルが存在するだけでは、復旧の準備が完了したとはいえません。
削除対象の期間を、Mountまたは隔離したRestore環境で実際に検索してください。
元データ、バックアップ、別途作成した集計データの保持期間も、それぞれ定める必要があります。
環境別のコマンドは[バックアップ・リストア・マウント](/ja/dbms/operations-configuration-recovery/backup-restore-mount/)に従ってください。
## データとディスク領域
行が検索結果から消える時点と、OS上のファイル領域が回収される時点は異なる場合があります。
入力量、残っている行の最古の時刻、インデックスとストレージのクリーンアップ状態、ディスク使用量を併せて確認してください。
削除直後にディスク使用量が減らないことを理由に、さらに広い期間を削除しないでください。
削除結果が予想と異なる場合は、境界時刻と適用されたポリシーを確認してください。
保存義務があるデータでは追加の削除を止め、担当者と対象範囲を先に確認することを推奨します。
---
title: "7.8 制約、エラー、トラブルシューティング"
url: https://docs.machbase.com/ja/dbms/log-table-usage/constraints-errors-troubleshooting/
language: ja
kind: page
---
# 7.8 制約、エラー、トラブルシューティング
失敗したSQLを繰り返しても原因は解消せず、状態が複雑になることがあります。
まず未サポートの操作か、入力値やオブジェクトの状態の問題かを区別してください。
この節では、症状に応じて確認箇所を絞り込みます。
## 機能のサポート範囲
| 要求 | LOGの対応 | 代替方法 |
|---|---|---|
| 一般的なUPDATE | 未サポート | 訂正イベントを設計するか、更新可能なテーブルを選択 |
| 任意条件のDELETE WHERE | 未サポート | BEFORE・OLDEST・EXCEPTを使用するか、モデルを変更 |
| PRIMARY KEY・UNIQUE制約 | 未サポート | 収集段階で重複を処理するか、別のテーブルを選択 |
| 値・範囲インデックス | LSMをサポート | 型と条件に合わせて選択 |
| 単語検索 | KEYWORDをサポート | VARCHAR・TEXTに作成し、SEARCH・ESEARCHを使用 |
| 分析用BITMAPインデックス | サポート条件内で使用 | 型・エンコーディング・値の分布を確認 |
| TEXT自体のORDER BY・GROUP BY | 未サポート | コード・重要度・時刻を別カラムに格納 |
## 症状別の診断
| 症状 | 最初の確認事項 | 対処 |
|---|---|---|
| 指定した到着時刻と保存時刻が異なる | 直前の時刻とTIME_INVERSION_MODE | 補正の有無を確認し、発生時刻は別に保持 |
| SEARCHでインデックス関連エラー | 対象カラムのKEYWORDインデックス | 型・テーブル・インデックス名を確認 |
| 単語があるのに検索されない | SEARCHのトークンとLIKEの部分文字列の違い | 元の1行で両方の結果を比較 |
| インデックス作成後も検索が遅い | 実行計画・構築状態・時間範囲 | 反映状態を確認後、代表的な負荷を測定 |
| カラム長の変更に失敗 | 既存の型と新しい長さ | VARCHARの拡張のみ使用し、最大長を確認 |
| MINMAXの変更に失敗 | 可変長型かどうか | LOGで対応する固定長カラムのみを対象にする |
| NOT NULLへの変更に失敗 | 既存のNULL行 | 既存データの検査とNOCHECKの意味を区別 |
| 同じイベントが複数表示される | 元のID・再試行・ファイル再処理 | 再送ポリシーを確認し、任意行の削除で解決しない |
| DDL実行中にリソース使用中エラー | 入力・検索とDDLの競合 | 実行時刻を調整して再確認 |
サーバー設定とインデックス一覧は次のように確認できます。
```sql
SELECT NAME, VALUE FROM V$PROPERTY
WHERE NAME IN ('DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE', 'TABLE_SCAN_DIRECTION');
SHOW INDEXES;
```
設定の確認と変更は別の操作です。
原因を特定する前に、本番サーバーのグローバル設定を変更しないでください。
## エラーの再現と解決
```sql
CREATE LOG TABLE ch7_error (event_id INTEGER, message TEXT);
INSERT INTO ch7_error VALUES (1, 'connection timeout');
SELECT event_id, message FROM ch7_error;
```
1行が返されます。以下のSQLはそれぞれ意図的に失敗します。
通常の実習とまとめて実行せず、確認したい文だけを個別に実行してください。
```sql
-- KEYWORDインデックスがない状態です。
SELECT event_id FROM ch7_error WHERE message SEARCH 'timeout';
-- TEXT自体のソート・グループ化はサポートしていません。
SELECT message FROM ch7_error ORDER BY message;
SELECT message, COUNT(*) FROM ch7_error GROUP BY message;
-- LOGは一般的なUPDATE・条件付きDELETEをサポートしていません。
UPDATE ch7_error SET message = 'fixed' WHERE event_id = 1;
DELETE FROM ch7_error WHERE event_id = 1;
-- TEXTをVARCHARに変換するコマンドではありません。
ALTER TABLE ch7_error MODIFY COLUMN (message VARCHAR(4096));
```
インデックスを作成し、サポートされる検索方法で確認します。
```sql
CREATE INDEX ch7_error_msg ON ch7_error(message) INDEX_TYPE KEYWORD;
EXEC TABLE_FLUSH(ch7_error);
EXEC INDEX_FLUSH(ch7_error);
SELECT event_id, message FROM ch7_error
WHERE message SEARCH 'timeout'
ORDER BY event_id;
DROP TABLE ch7_error;
```
行1が返されることを確認してください。インデックスを追加しても、TEXTのソートやLOGのUPDATEは使用できません。
## 保持ポリシーの診断
期限切れの行が残る場合は、適用ポリシー、実行周期、LAST_DELETED_TIME、実際の`_arrival_time`を合わせて確認してください。
`event_time`だけを見て削除失敗と判断しないでください。
関連する実習は[運用とデータライフサイクル](../operations-lifecycle/)にあります。
問題が続く場合は、サーバーバージョンとEdition、テーブルDDL、失敗したSQL、エラー全文、代表的な入力値を用意してください。
パスワードと機密ログを伏せて共有してください。
全データを送るより、同じ症状を再現する小さな例のほうが原因の特定に役立ちます。
---
title: "7.9 活用パターンとシナリオ"
url: https://docs.machbase.com/ja/dbms/log-table-usage/patterns-scenarios/
language: ja
kind: page
---
# 7.9 活用パターンとシナリオ
実際の分析では、時刻、ホスト、重要度、メッセージを併せて確認します。
各機能を個別に試したら、「どのサーバーでどのエラーが増えたか」という問いに結び付けてみましょう。
この実習は、前の節のテーブルがなくても実行できます。
## 元のイベントと現在の状態
LOGにはイベントが発生するたびに新しい行を追加します。
機器の現在の名前・場所などの変更可能なマスターデータはLOOKUPに分離できますが、
過去の状態も必要なら、その時点の値をイベントに記録するか、履歴を別途設計する必要があります。
セキュリティイベントや処理の追跡にも同じ方法を適用できます。
センサー名ごとの計測値の集計が中心ならTAG、業務行の更新やトランザクションが中心ならTRANSACTIONを先に検討してください。
## ログとインデックスの作成
実行日に依存せず時間条件を比較できるよう、到着時刻を明示します。
空のテーブルに昇順で入力する実習です。通常の収集では、元の発生時刻を別のDATETIMEカラムに保持することを推奨します。
```sql
CREATE LOG TABLE ch7_app (
event_id INTEGER,
host VARCHAR(32),
level VARCHAR(16),
message TEXT
);
CREATE INDEX ch7_app_message ON ch7_app(message) INDEX_TYPE KEYWORD;
INSERT INTO ch7_app(_arrival_time, event_id, host, level, message)
VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'),
1, 'web-01', 'INFO', 'service started');
INSERT INTO ch7_app(_arrival_time, event_id, host, level, message)
VALUES (TO_DATE('2026-01-01 10:10:00', 'YYYY-MM-DD HH24:MI:SS'),
2, 'web-01', 'WARN', 'slow response');
INSERT INTO ch7_app(_arrival_time, event_id, host, level, message)
VALUES (TO_DATE('2026-01-01 10:20:00', 'YYYY-MM-DD HH24:MI:SS'),
3, 'web-02', 'ERROR', 'database timeout');
INSERT INTO ch7_app(_arrival_time, event_id, host, level, message)
VALUES (TO_DATE('2026-01-01 10:30:00', 'YYYY-MM-DD HH24:MI:SS'),
4, 'web-02', 'ERROR', 'connection refused');
INSERT INTO ch7_app(_arrival_time, event_id, host, level, message)
VALUES (TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'),
5, 'web-01', 'INFO', 'normal service');
EXEC TABLE_FLUSH(ch7_app);
EXEC INDEX_FLUSH(ch7_app);
SELECT COUNT(*) AS received_rows FROM ch7_app;
```
入力件数は5です。実習を繰り返す前に、最後のDROPまで実行したことを確認してください。
単純な再送は重複行につながる場合があります。
## エラーと時間帯による検索
```sql
SELECT event_id, host, message FROM ch7_app
WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND _arrival_time < TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND message SEARCH 'timeout'
ORDER BY event_id;
SELECT event_id, host, level, message FROM ch7_app
WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND _arrival_time < TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND level = 'ERROR'
ORDER BY event_id;
```
最初のクエリはweb-02のイベント3、2番目はイベント3と4を選択します。
特定の単語から検索を始め、分析では同じホスト・時間帯の他のエラーも確認する流れです。
検索範囲を広げるときは、時間条件をすべて外すのではなく、必要な区間だけを広げてください。
## 時間別・重要度別の集計
```sql
SELECT TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24') AS event_hour,
level, COUNT(*) AS event_count
FROM ch7_app
WHERE _arrival_time >= TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND _arrival_time < TO_DATE('2026-01-01 12:00:00', 'YYYY-MM-DD HH24:MI:SS')
GROUP BY TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24'), level
ORDER BY event_hour, level;
```
| event_hour | level | event_count |
|---|---|---|
| 2026-01-01 10 | ERROR | 2 |
| 2026-01-01 10 | INFO | 1 |
| 2026-01-01 10 | WARN | 1 |
| 2026-01-01 11 | INFO | 1 |
このクエリは元のLOGを読み取って集計します。TAGのROLLUPを自動的に使用するクエリではありません。
データが増えたら、検索区間と実行計画を確認し、事前集計が必要かを別途判断してください。
固定時刻のデータに`DURATION 1 HOUR`を適用しないよう注意してください。
この条件は現在時刻を基準にするため、実行日が変わるとサンプルが選択されない場合があります。
運用時の直近ログ検索と、再現用の固定時刻検索を区別してください。
## 収集と保持の管理
継続的な収集は[Append入力](../data-input-mutation/)を参照して構成できます。
長期運用では[保持ポリシー](../operations-lifecycle/)も定めてください。
元のログ、バックアップ、別途作成する集計データでは、必要な保持期間が異なる場合があります。
```sql
DROP TABLE ch7_app;
```
ここまでの結果が一致したら、実際のログ数件でフィールドとメッセージを置き換えてください。
収集全体を一度に移行するより、小さなサンプルで同じ問いに答えられるか確認すると、問題を見つけやすくなります。
---
title: "7.10 _arrival_timeの時間モデル"
url: https://docs.machbase.com/ja/dbms/log-table-usage/arrival-time-model/
language: ja
kind: page
---
# 7.10 _arrival_timeの時間モデル
元のログには昨日の時刻が記録されていても、クエリでは今日収集したデータとして扱われることがあります。
発生時刻と収集時刻を混同すると、正常に取り込まれたデータも欠落したように見えます。
LOGのクエリと保持ポリシーを設計するには、まずこの2つの時刻を区別します。
## 発生時刻と到着時刻
`event_time`などのユーザー定義DATETIMEカラムは、イベントが発生した時刻を表します。
自動生成される`_arrival_time`は、LOGの時間範囲アクセスと保持期間に基づく削除の基準です。
省略するとサーバー時刻が使われますが、明示的な入力や時刻逆転の補正もあるため、
常に実際のネットワーク受信時刻を表すとは限りません。
DATETIMEはナノ秒単位の値を表現します。サーバーの時計が毎回ナノ秒精度で時刻を測定するという意味ではありません。
保存後にLOGテーブルのUPDATEで時刻を修正することもできません。
## 遅延イベントの検索
次の例では、空の実習用テーブルに到着時刻を昇順で指定して挿入します。
```sql
CREATE LOG TABLE ch7_time (
event_id INTEGER,
event_time DATETIME,
message VARCHAR(64)
);
INSERT INTO ch7_time(_arrival_time, event_id, event_time, message)
VALUES (TO_DATE('2026-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 1,
TO_DATE('2026-01-02 09:59:00', 'YYYY-MM-DD HH24:MI:SS'), 'normal arrival');
INSERT INTO ch7_time(_arrival_time, event_id, event_time, message)
VALUES (TO_DATE('2026-01-02 10:01:00', 'YYYY-MM-DD HH24:MI:SS'), 2,
TO_DATE('2026-01-01 23:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'delayed arrival');
SELECT event_id
FROM ch7_time
WHERE event_time >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
AND event_time < TO_DATE('2026-01-02', 'YYYY-MM-DD')
ORDER BY event_id;
SELECT event_id
FROM ch7_time
DURATION FROM TO_DATE('2026-01-02 10:00:00', 'YYYY-MM-DD HH24:MI:SS')
TO TO_DATE('2026-01-02 10:01:00', 'YYYY-MM-DD HH24:MI:SS');
```
発生時刻による検索ではイベント2だけが、到着時刻による検索ではイベント1と2が選択されます。
遅れて到着したイベントの発生時刻を変更する必要はありません。
## 時刻逆転と補正
`DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE`は、直前の到着時刻より小さい値が入力された場合の処理を指定します。
現在のStandard実装の動作は次のとおりです。
| 値 | 時刻が逆転した入力の処理 |
|---|---|
| 1(デフォルト) | 直前に保存した`_arrival_time`より1ns大きい値に補正 |
| 0 | 時刻逆転エラーとして入力を拒否 |
同じ時刻は逆転に該当しないため、この規則だけで各行の時刻が一意になるわけではありません。
同時刻の行にも固定の順序が必要なら、イベント番号などの追加条件をORDER BYに指定してください。
次の任意の実習では、先ほどのテーブルを使います。
まず設定を確認し、値が1の検証環境でのみ実行してください。
この例のために本番サーバーの設定を変更しないでください。
```sql
SELECT NAME, VALUE FROM V$PROPERTY
WHERE NAME = 'DISK_COLUMNAR_TABLE_TIME_INVERSION_MODE';
```
```sql
-- 設定値1で実行します。値が0の場合は入力エラーが想定されます。
INSERT INTO ch7_time(_arrival_time, event_id, event_time, message)
VALUES (TO_DATE('2026-01-02 09:00:00', 'YYYY-MM-DD HH24:MI:SS'), 3,
TO_DATE('2026-01-02 08:59:00', 'YYYY-MM-DD HH24:MI:SS'), 'inverted arrival');
SELECT event_id,
TO_CHAR(_arrival_time, 'YYYY-MM-DD HH24:MI:SS mmm:uuu:nnn') AS stored_time
FROM ch7_time
ORDER BY event_id;
```
設定値が1の場合、イベント3の保存時刻は入力した09:00ではなく、
`2026-01-02 10:01:00 000:000:001`になります。発生時刻は入力値のままです。
したがって、時刻逆転の「許可」は、過去の時刻を無条件に保持するという意味ではありません。
## データ移行時の注意事項
元の`_arrival_time`を保持するには、空の移行先に昇順で入力することが基本です。
ソート済みでも、移行先により新しい時刻の行がある場合や、別の入力が割り込む場合は補正やエラーが発生し得ます。
同じテーブルで移行と通常のリアルタイム収集を混在させないでください。
`DURATION`は`event_time`ではなく`_arrival_time`を使用します。
タイムゾーンと日付書式を合わせても範囲が異なる場合は、クエリが参照する時間カラムを再確認してください。
境界と出力順序については、[クエリの実習](../query-analysis/)で説明します。
```sql
DROP TABLE ch7_time;
```
時刻に関する問題を問い合わせる際は、元の時刻、保存された時刻、設定値を用意してください。
3つを比較すると、変換と補正のどちらの段階で差が生じたかを判断しやすくなります。
---
title: "7.11 テキスト検索とKEYWORDインデックス"
url: https://docs.machbase.com/ja/dbms/log-table-usage/text-search-keyword-index/
language: ja
kind: page
---
# 7.11 テキスト検索とKEYWORDインデックス
メッセージに同じ文字が含まれていても、SEARCHとLIKEの結果は異なる場合があります。
SEARCHは索引化された単語を検索し、LIKEは元の文字列にパターンを適用するためです。
性能を比較する前に、どの行を検索するかを明確にします。
## 検索データの準備
```sql
CREATE LOG TABLE ch7_search (
event_id INTEGER,
message TEXT
);
CREATE INDEX ch7_search_msg ON ch7_search(message) INDEX_TYPE KEYWORD;
INSERT INTO ch7_search VALUES (1, 'ERROR connection timeout');
INSERT INTO ch7_search VALUES (2, 'connection slowly refused');
INSERT INTO ch7_search VALUES (3, 'pretimeout marker');
INSERT INTO ch7_search VALUES (4, 'normal service');
INSERT INTO ch7_search VALUES (5, NULL);
INSERT INTO ch7_search VALUES (6, '대한민국 연결 오류');
INSERT INTO ch7_search VALUES (7, 'ERR-1001 network');
INSERT INTO ch7_search VALUES (8, 'timeout refused connection');
EXEC TABLE_FLUSH(ch7_search);
EXEC INDEX_FLUSH(ch7_search);
```
サンプルの`event_id`で結果を比較します。メッセージはTEXTなので、ソート基準には使用しません。
LOGのVARCHARでも同じKEYWORD検索を使用できます。
## SEARCHとNOT SEARCH
```sql
SELECT event_id FROM ch7_search WHERE message SEARCH 'timeout' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message SEARCH 'connection refused' ORDER BY event_id;
SELECT event_id FROM ch7_search
WHERE message SEARCH 'connection' AND message SEARCH 'refused'
ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message NOT SEARCH 'timeout' ORDER BY event_id;
```
| 条件 | 選択されるevent_id | 理由 |
|---|---|---|
| SEARCH 'timeout' | 1, 8 | pretimeoutは別の単語 |
| SEARCH 'connection refused' | 2, 8 | 両方の単語が存在する |
| 2つのSEARCH条件をANDで結合 | 2, 8 | 同じメッセージ内の両方の単語を確認 |
| NOT SEARCH 'timeout' | 2, 3, 4, 6, 7 | 対象の単語がなく、NULL行は除外 |
複数単語のSEARCHは、語順や隣接性を保証するフレーズ検索ではありません。
イベント2には間に別の単語があり、イベント8は逆順ですが、両方とも選択されます。
他のカラムにもSEARCHを使用するには、そのカラムにも対応するインデックスが必要です。
デフォルトのトークン化では、通常のASCII単語は小文字に正規化されます。
例えば、イベント1の`ERROR`は`SEARCH 'error'`でも検索されます。
これをすべてのUnicode文字に対する言語別の大文字・小文字処理と解釈しないでください。
### 韓国語のトークン分割
```sql
SELECT event_id FROM ch7_search WHERE message SEARCH '대한' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message SEARCH '연결' ORDER BY event_id;
```
どちらもイベント6が選択されます。デフォルトモードでは、`대한민국`は`대한`、`한민`、`민국`のような
重複する2-gramとして索引化されます。形態素や文の意味を理解する検索ではありません。
空白・句読点・1文字の値・英語と韓国語の混在値ではトークン境界が変わる場合があるため、実際のサンプルで確認してください。
MODEなどのインデックスオプションを変更すると、トークン化も変わる場合があります。
## ESEARCHによる拡張検索
```sql
SELECT event_id FROM ch7_search WHERE message ESEARCH 'time%' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message ESEARCH '%time%' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message ESEARCH 'err%' ORDER BY event_id;
```
| パターン | 選択されるevent_id | 意味 |
|---|---|---|
| time% | 1, 8 | timeで始まる単語 |
| %time% | 1, 3, 8 | timeを含む単語 |
| err% | 1, 7 | errorやerrのようにerrで始まる単語 |
`time%`は単語の途中にあるtimeまで検索するものではありません。
また、ESEARCHは原文全体にLIKEを適用することと同じではありません。
空白や句読点をまたぐ原文パターンを、そのままESEARCHに移さないでください。
複雑な複数条件は、個別のSEARCH・ESEARCH条件をAND・ORで結合し、意味を明示してください。
現在の比較処理では、ESEARCHはASCIIの大文字と小文字を区別しません。
対象キーワードが広く一致するほど検索コストも増えるため、常にLIKEより高速とは限りません。
この例はASCIIキーワードのパターンを対象としています。
`NOT ESEARCH`構文はサポートしていません。`NOT SEARCH`や`NOT LIKE`に変更すると、検索の意味も変わります。
除外する行を再定義し、NULLの扱いまで確認してください。
## LIKEとNOT LIKE
```sql
SELECT event_id FROM ch7_search WHERE message LIKE '%TIMEOUT%' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message LIKE 'ERR-____' ORDER BY event_id;
SELECT event_id FROM ch7_search WHERE message NOT LIKE '%timeout%' ORDER BY event_id;
```
最初のクエリはイベント1・3・8、2番目は0件、3番目はイベント2・4・6・7を返します。
イベント7のメッセージは`ERR-1001`の後にも文字列があるため、全体パターン`ERR-____`に一致しません。
`%`は0文字以上、`_`は1文字を表します。
リテラルの`%`・`_`・バックスラッシュを検索する場合は、バックスラッシュのエスケープ規則も確認してください。
LIKEも現在のASCII比較では大文字と小文字を区別しません。
KEYWORDインデックスは使用しませんが、WHEREの他の条件や時間範囲で検査する行を減らせます。
したがって、LIKEがあるという理由だけで常にテーブル全体を読むと説明するのも正確ではありません。
## REGEXPとREGEXP_LIKE
```sql
SELECT event_id FROM ch7_search
WHERE message REGEXP '^ERR-[0-9]+'
ORDER BY event_id;
SELECT event_id FROM ch7_search
WHERE message NOT REGEXP 'timeout'
ORDER BY event_id;
```
最初のクエリはイベント7、2番目はイベント2・4・6・7を返します。
REGEXPは正規表現パターンに一致する部分があるかを検査します。
文字列の先頭や末尾を制限するには、`^`・`$`を明示してください。
関数として使用する場合は`REGEXP_LIKE`を使用します。
現在、この関数の入力はVARCHARである必要があり、パターンとオプションも定数VARCHARである必要があります。
先ほどのTEXTカラムをそのまま渡すと型エラーになるため、別のサンプルを用意します。
```sql
CREATE LOG TABLE ch7_regexp_fn (event_id INTEGER, message VARCHAR(200));
INSERT INTO ch7_regexp_fn VALUES (1, 'ERROR connection timeout');
INSERT INTO ch7_regexp_fn VALUES (5, NULL);
SELECT event_id,
REGEXP_LIKE(message, 'error') AS case_sensitive,
REGEXP_LIKE(message, 'error', 'i') AS case_insensitive
FROM ch7_regexp_fn
WHERE event_id IN (1, 5)
ORDER BY event_id;
```
イベント1の結果はそれぞれ0・1、メッセージがNULLのイベント5は両方ともNULLです。
デフォルトの正規表現比較は大文字と小文字を区別し、`i`オプションは区別しない比較です。
区別する比較を明示するには`c`を使用できます。
正規表現はKEYWORDインデックスで直接処理されません。
時間条件やSEARCHで対象を絞れますが、先行条件で必要な行を除外すると、後続の正規表現でその行を取り戻すことはできません。
## TEXTの制約と検索性能
TEXTは最大64MiBの原文を格納できますが、TEXT自体のORDER BY・GROUP BYはサポートしていません。
ソート・集計するデバイス・エラーコード・重要度は別カラムに格納してください。
同じデータでインデックスの有無、構築状態、検索範囲を確認してから性能を比較します。
```sql
DROP TABLE ch7_regexp_fn;
DROP TABLE ch7_search;
```
検索結果が異なる場合は、元の1行と使用したパターンを併せて確認してください。
単語を探すのか、原文の一部を探すのかを区別するだけで解決する場合も多くあります。
---
title: "7.12 ネットワーク型のクエリ"
url: https://docs.machbase.com/ja/dbms/log-table-usage/regex-network-query/
language: ja
kind: page
---
# 7.12 ネットワーク型のクエリ
IPアドレスを文字列で保存すると読みやすい反面、文字列のソート順とアドレス範囲の順序が同じだと考えがちです。
アドレスの比較が目的ならIPV4・IPV6型を使用し、元の表記も必要な場合だけ別の文字列を併せて保存してください。
## ネットワークデータの準備
```sql
CREATE LOG TABLE ch7_network (
event_id INTEGER,
src_ip IPV4,
dst_ip IPV6,
dst_port INTEGER
);
INSERT INTO ch7_network VALUES (1, '192.0.2.1', '2001:db8::1', 80);
INSERT INTO ch7_network VALUES (2, '192.0.2.255', '2001:db8::2', 65535);
INSERT INTO ch7_network VALUES (3, '198.51.100.1', '2001:db8::3', 443);
INSERT INTO ch7_network VALUES (4, NULL, NULL, NULL);
SELECT event_id, src_ip, dst_ip, dst_port FROM ch7_network ORDER BY event_id;
```
4行が返されます。ポートにはINTEGERを使用します。
USHORTの最大値65535はNULLの予約値なので、ポートの全範囲をそのまま表現する用途には適しません。
## 等価比較と範囲検索
```sql
SELECT event_id FROM ch7_network
WHERE src_ip BETWEEN '192.0.2.1' AND '192.0.2.255'
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE src_ip IN ('192.0.2.1', '198.51.100.1')
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE dst_ip = '2001:db8::2'
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE dst_ip BETWEEN '2001:db8::1' AND '2001:db8::2'
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE src_ip IS NULL
ORDER BY event_id;
```
| 条件 | 選択されるevent_id |
|---|---|
| IPv4 BETWEEN | 1, 2 |
| IPv4 IN | 1, 3 |
| IPv6等価比較 | 2 |
| IPv6 BETWEEN | 1, 2 |
| IPv4 IS NULL | 4 |
BETWEENは両端のアドレスを含みます。この例のIPv4範囲はCIDRの意味を自動適用するものではなく、
明示的に指定した2つのアドレス間の範囲です。
ネットワーク範囲への所属を判定する場合は、次の`CONTAINED`を使用してください。
NULLは`= NULL`ではなく`IS NULL`で検査します。
## CIDRによる判定
アドレスが特定のネットワークに属するかを検査するには、`CONTAINED`を使用します。
範囲は必ず`アドレス/prefix`形式で指定します。IPv4とIPv6の両方で使用できます。
```sql
SELECT event_id FROM ch7_network
WHERE src_ip CONTAINED '192.0.2.0/24'
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE dst_ip CONTAINED '2001:db8::/32'
ORDER BY event_id;
SELECT event_id FROM ch7_network
WHERE src_ip NOT CONTAINED '192.0.2.0/24'
ORDER BY event_id;
```
| 条件 | 選択されるevent_id |
|---|---|
| IPv4 `CONTAINED '192.0.2.0/24'` | 1, 2 |
| IPv6 `CONTAINED '2001:db8::/32'` | 1, 2, 3 |
| IPv4 `NOT CONTAINED '192.0.2.0/24'` | 3 |
向きを逆にした`'192.0.2.0/24' CONTAINS src_ip`も同じ意味です。
左辺にネットワーク、右辺にアドレスを指定する形式が`CONTAINS`で、その逆が`CONTAINED`です。
prefixを省略して`CONTAINED '192.0.2.0'`と書くと、ネットワークとして解釈できずエラーになります。
アドレスがNULLのイベント4はいずれの条件でも選択されません。
未収集のアドレスも数える場合は、`IS NULL`条件を別途指定してください。
## アドレス形式と元の表記の保持
IPv4だけを入力する場合はIPV4、IPv6を入力する場合はIPV6でスキーマを定義します。
両方を扱う場合は、入力変換とカラム分離のポリシーを先に定め、実際のサンプルで検証してください。
暗黙の変換が常に意図どおりに元のアドレスを正規化するとは限りません。
出力文字列には注意が必要です。同じIPv6アドレスでも、元の圧縮表記と検索結果の表記が異なる場合があります。
原文を証跡として残す必要がある場合は、アドレス型カラムと原文カラムを分離すると明確です。
大量データでは、アドレス条件に加えて`_arrival_time`の範囲を制限し、実行計画を確認してください。
メッセージの正規表現検索は[テキスト検索](../text-search-keyword-index/#regex)と
[SQL関数リファレンス](/ja/dbms/reference/sql/functions/)を参照してください。
```sql
DROP TABLE ch7_network;
```
アドレス検索の結果が予想と異なる場合は、元の文字列、入力型、範囲の両端を並べて比較してください。
文字列表現の違いか、実際のアドレス範囲の違いかを区別しやすくなります。
---
title: "8. TRANSACTIONテーブルの活用"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/
language: ja
kind: section
---
# 8. TRANSACTIONテーブルの活用
元のログを蓄積する処理と、注文状態・在庫・機器情報を変更する処理では性質が異なります。
状態を変更する業務では、「何行が変わったか」「途中で失敗するとどこまで戻るか」
「別の接続が同時に更新するとどうなるか」も確認する必要があります。
TRANSACTIONテーブルは、このようなリレーショナルなクエリと変更のためのStandard Edition専用テーブルです。
この章では、小さなサンプルで結果を確認しながら、スキーマ、更新、トランザクション、同時アクセス、復旧を説明します。
内部ではSQLiteストレージを使用しますが、公開構文とサポート範囲はMachbase SQLを基準にしてください。
SQLiteや他のRDBMSの全機能をそのまま使用できるわけではありません。
## この章の構成
| 節 | 確認内容 |
|---|---|
| [8.1 概要と選択基準](./overview-use-criteria/) | LOG・TAG・LOOKUPとの役割の区別 |
| [8.2 テーブル構造とスキーマ](./table-structure-schema/) | 識別子・業務キー・型・制約の設計 |
| [8.3 作成、変更、削除](./create-alter-drop/) | DDLの実行と既存データの確認 |
| [8.4 データ入力と変更](./data-input-mutation/) | 条件付き更新・削除・コピー・Append |
| [8.5 クエリと分析](./query-analysis/) | フィルター・ソート・集計・JSON検索 |
| [8.6 インデックスとパフォーマンス](./index-performance/) | PK・UNIQUE・複合・JSONパスインデックス |
| [8.7 運用とデータライフサイクル](./operations-lifecycle/) | バッチ削除と運用確認の基準 |
| [8.8 制約、エラー、トラブルシューティング](./constraints-errors-troubleshooting/) | 症状別の確認と再試行判断 |
| [8.9 トランザクション](./transaction/) | 文の失敗・ROLLBACK・コミットの保証範囲 |
| [8.10 ロック、競合、busy timeout](./locking-conflict-timeout/) | 2接続の競合とスナップショットの再試行 |
| [8.11 JOINとリレーショナルクエリの設計](./join-relational-query/) | 結合で増加・除外される行の確認 |
| [8.12 バックアップ、リストア、マウント](./backup-restore-mount/) | バックアップ時点のデータの実検証 |
| [8.13 INSERT ON DUPLICATE KEY UPDATE](./insert-on-duplicate-key-update/) | 挿入・更新の分岐と重複処理 |
自動採番の共通構文は[AUTO_INCREMENT](/ja/dbms/reference/sql/syntax/auto-increment-syntax/)を参照してください。
## 実習環境と実行単位
SQL実習はDBMS 8.7 Standard Editionの検証環境を対象にします。
各節で`ch8_`接頭辞のオブジェクトを準備・削除するため、他の節の実行結果には依存しません。
テーブル・インデックスの作成権限が必要で、バックアップの実習には別途権限とサーバー上のパスが必要です。
BEGINからCOMMIT・ROLLBACKまでは同じ接続で実行してください。
2セッションの実習では、指定したA・Bの順序に従ってください。
意図的に失敗するSQLは通常の流れと分離しています。
実習を再実行する前に、クリーンアップSQLまで完了したことを確認してください。
注意: テーブル名にTRANSACTIONが含まれていても、すべての操作とすべての障害を一括で戻せるわけではありません。
DDL、他のタイプへの書き込み、障害時の複数テーブルのコミット境界は、[8.9 トランザクション](./transaction/)で先に確認してください。
---
title: "8.1 概要と選択基準"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/overview-use-criteria/
language: ja
kind: page
---
# 8.1 概要と選択基準
機器の測定値は継続的に蓄積されますが、点検状態や在庫数量は既存値を変更する必要があります。
両方を同じモデルで処理すると、元データの保持と状態変更の要件が混在しがちです。
変更可能な業務データをTRANSACTIONに、元の時系列データをTAG・LOGに格納する構成を先に検討してください。
## TRANSACTIONテーブルの特性
TRANSACTIONはSELECT・INSERT・UPDATE・DELETE、PRIMARY KEY、UNIQUE INDEX、セカンダリインデックスをサポートします。
Standard Edition専用で、次の3つの構文は同じテーブルを作成します。
| 構文 | 意味 |
|---|---|
| CREATE TABLE | タイプを省略したデフォルトのTRANSACTION作成 |
| CREATE TRANSACTION TABLE | タイプを明示した作成 |
| CREATE TXN TABLE | 短縮形による作成 |
公開文書と運用スクリプトでは、タイプが明確なCREATE TRANSACTION TABLEを推奨します。
CREATE RDB TABLE・CREATE TRX TABLEはサポートしていません。
Clusterでは上の3つの作成構文をすべて使用できません。LOGはCREATE LOG TABLEで明示します。
## 状態変更とロールバック
```sql
CREATE TRANSACTION TABLE ch8_overview (
item_id LONG PRIMARY KEY,
qty INTEGER NOT NULL
);
INSERT INTO ch8_overview VALUES (42, 10);
BEGIN;
UPDATE ch8_overview SET qty = qty - 3 WHERE item_id = 42 AND qty >= 3;
SELECT item_id, qty FROM ch8_overview;
ROLLBACK;
SELECT item_id, qty FROM ch8_overview;
DROP TABLE ch8_overview;
```
同じ接続では、トランザクション内の検索は数量7、ROLLBACK後の検索は10を返します。
`qty >= 3`は、在庫不足の場合に変更しないための業務条件です。
UPDATEがエラーなしで終了すれば業務も成功した、と判断しないよう注意してください。
条件に一致する行がなければ、変更件数は0になり得ます。
アプリケーションでは影響行数が想定した1であることを確認し、次の処理かロールバックかを決める必要があります。
SQL例の数値を置き換えることより、この確認手順が重要です。
## 他のテーブルとの比較
| 主な要件 | 最初に検討するテーブル |
|---|---|
| センサー名ごとの測定値とROLLUP | TAG |
| 更新しないログ・イベントの元データ | LOG |
| 小規模な現在のマスターデータ | LOOKUP |
| リレーショナルなDMLと明示的トランザクション | TRANSACTION |
| 再起動後に消失してもよいメモリ上の状態 | VOLATILE |
TRANSACTIONには、機器の点検状態、業務履歴、別途作成した要約結果などを格納できます。
大量の元データの収集では、TAG・LOGとスループット・取り込み方法を比較してください。
TRANSACTIONもAppendをサポートしますが、TAG・LOGと同じスループットやバッチ境界を前提にしないでください。
[取り込み方式](../data-input-mutation/)で具体的に区別します。
LOOKUPは、TRANSACTIONの全機能を代替するテーブルではありません。
Clusterでリレーショナルトランザクションが必須の場合は、別のRDBMSを含む構成を検討する必要があります。
## 設計基準
1行を識別するキーと、重複を防ぐ業務キーを区別してください。
内部番号にはPRIMARY KEY、外部システムのコードなど別の一意値にはUNIQUE INDEXが必要な場合があります。
自動採番を使用しても、業務キーの重複は自動的には防げません。
続いて、頻繁に実行するWHERE条件と業務の成功基準を決めます。
トランザクションの終了位置とエラー時の確認事項まで決めておくと、同時要求や接続障害が発生しても対応を一貫させられます。
[スキーマ](../table-structure-schema/)と[トランザクション](../transaction/)を併せて確認してください。
---
title: "8.2 テーブル構造とスキーマ"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/table-structure-schema/
language: ja
kind: page
---
# 8.2 テーブル構造とスキーマ
自動採番があれば重複の問題は解決したと考えがちです。
しかし、同じ外部機器が異なる番号で2回登録されることは依然として可能です。
行の識別キーと業務上の重複を防ぐキーを区別することが、スキーマ設計の出発点です。
## 内部識別子と業務キー
次の例では、内部番号と外部機器コードを別々に管理します。
```sql
CREATE TRANSACTION TABLE ch8_schema (
id LONG PRIMARY KEY AUTO_INCREMENT,
external_code VARCHAR(64) NOT NULL,
device_name VARCHAR(128) NOT NULL,
price DECIMAL(18,2),
state JSON,
updated_at DATETIME
);
CREATE UNIQUE INDEX ch8_schema_code ON ch8_schema(external_code);
INSERT INTO ch8_schema(external_code, device_name, price, state, updated_at)
VALUES ('ERP-01', 'Pump A', 19900.25, '{"status":"NORMAL"}',
TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'));
SELECT external_code, device_name, price, state->'$.status' AS status
FROM ch8_schema;
```
ERP-01の1行、価格19900.25、状態NORMALが返されます。
idはサーバーが付与します。連続番号や欠番のない発行を業務条件にしないでください。
発行番号の取得方法は、使用するSDKと[AUTO_INCREMENT](/ja/dbms/reference/sql/syntax/auto-increment-syntax/)を確認してください。
## PRIMARY KEYとUNIQUE
TRANSACTIONのPRIMARY KEYはテーブルごとに1つで、単一列です。
列の後にPRIMARY KEYを指定するか、既存テーブルにCREATE PRIMARY KEY INDEXで追加できます。
NULLや重複を含むデータには作成できません。
複数列の組み合わせを一意にするには、複合UNIQUE INDEXを使用します。
他のDBMSのCREATE TABLE内のUNIQUE・FOREIGN KEY・テーブルレベルPRIMARY KEY構文を、そのまま持ち込まないでください。
一意性はテーブル作成後にCREATE UNIQUE INDEXで指定します。
UNIQUE INDEXのキーにNULLが含まれる場合、NULLを含むキー同士は重複とは見なされません。
コードが必須かつ一意である必要がある場合は、例のようにNOT NULLも宣言してください。
空文字列にも注意が必要です。Machbaseの空文字列とNULLの扱いも実際の取り込み方法で確認し、必須コードは収集段階で検証してください。
次のSQLはUNIQUE違反を確認する任意の実習です。通常の入力とは分けて実行してください。
```sql
-- 意図的に失敗: external_codeの重複
INSERT INTO ch8_schema(external_code, device_name)
VALUES ('ERP-01', 'Duplicate Pump');
```
失敗後もERP-01は1行のままである必要があります。
重複時に更新するには、[UPSERT](../insert-on-duplicate-key-update/)の別の規則を使用します。
## データ型の選択
| 値 | 型の選択 | 確認事項 |
|---|---|---|
| 識別子・数量 | SHORT・INTEGER・LONGとサポートされる符号なし型 | 範囲とNULL予約値 |
| 測定値・近似値 | FLOAT・DOUBLE | 浮動小数点の丸め |
| 金額・正確な小数 | DECIMAL(M,D)とNUMERICなどの別名 | 精度・小数桁数・入力変換 |
| コード・名前 | VARCHAR(n) | 文字数ではなくバイト長 |
| 長い文字列・バイナリ | TEXT/CLOB・BINARY/BLOB | 保存の対応とソート・関数・インデックスの対応を区別 |
| 発生・変更時刻 | DATETIME | 元のタイムゾーンと変換書式 |
| ネットワークアドレス | IPV4・IPV6 | アドレス形式と比較の意味 |
| 追加属性 | JSON | 頻繁に検索するパスと型 |
| 固定長の数値群 | 数値ARRAY | 要素型・長さ・列全体のNULLと要素のNULL |
全体の範囲は[データ型リファレンス](/ja/dbms/reference/sql/types/)、
金額は[DECIMAL](/ja/dbms/reference/sql/types/decimal-numeric-fixed-point/)を基準に確認してください。
例のDOUBLEを慣習的にすべての金額列に使用しないでください。
## 制約と入力検証
TRANSACTIONには少なくとも1つのユーザー列が必要です。
LOGの自動到着時刻や、TAGのMETADATA・BASETIME・BASEDISTANCEは使用できません。
外部キーが自動的に参照整合性を検査すると考えず、必要な関係の検証をアプリケーションとデータ点検手順に含めてください。
例のUNIQUE INDEXがあっても、機器名や価格の業務上の有効性まで検査されるわけではありません。
必須値、許可する状態、数量範囲は別途定義する必要があります。
```sql
SELECT COUNT(*) AS device_count FROM ch8_schema;
DROP TABLE ch8_schema;
```
クリーンアップ前の件数は1です。
スキーマ変更は[作成・変更・削除](../create-alter-drop/)、クエリのアクセス経路は
[インデックス設計](../index-performance/)で引き続き確認してください。
---
title: "8.3 作成、変更、削除"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/create-alter-drop/
language: ja
kind: page
---
# 8.3 作成、変更、削除
スキーマ変更では、コマンドの成否と同じくらい、既存データと取り込みプログラムの状態が重要です。
名前を変更した後に古いSQLを実行したり、インデックスが参照する列を先に削除したりするとエラーになります。
この節ではサンプルを入力した状態で、変更前後を確認します。
## テーブルの作成
```sql
CREATE TRANSACTION TABLE ch8_ddl (
id LONG,
code VARCHAR(32),
qty INTEGER
);
INSERT INTO ch8_ddl VALUES (1, 'P-01', 10);
```
## キーとインデックスの作成
```sql
CREATE PRIMARY KEY INDEX ch8_ddl_pk ON ch8_ddl(id);
CREATE UNIQUE INDEX ch8_ddl_code ON ch8_ddl(code);
CREATE INDEX ch8_ddl_qty ON ch8_ddl(qty);
SHOW INDEX ch8_ddl_code;
```
idは単一のPRIMARY KEY、codeは別の業務キーです。
既存データに重複やPRIMARY KEYのNULLがある場合は、作成に失敗することがあります。
複合的な一意性はCREATE UNIQUE INDEXで設定します。CREATE TABLE内のUNIQUE制約構文は未サポートです。
自動採番が必要な場合は、作成時に`LONG PRIMARY KEY AUTO_INCREMENT`を指定します。
この節のidは直接入力した値で、自動採番列ではありません。
2つの作成方式を同じオブジェクトに重複して実行しないでください。
[AUTO_INCREMENT](/ja/dbms/reference/sql/syntax/auto-increment-syntax/)に別の実習があります。
## 列の追加とデフォルト値
```sql
ALTER TABLE ch8_ddl ADD COLUMN (label VARCHAR(64));
ALTER TABLE ch8_ddl ADD COLUMN (status VARCHAR(16) DEFAULT 'NEW');
ALTER TABLE ch8_ddl ADD COLUMN (limits DECIMAL(12)[2] DEFAULT [10, 20]);
SELECT id, label, status, limits FROM ch8_ddl ORDER BY id;
```
行1のlabelはNULL、statusはNEW、limitsは[10, 20]です。
DEFAULTのないARRAY列を追加すると、既存行では配列全体がNULLになります。
`ADD COLUMN`の`DEFAULT`と`CREATE TABLE`の`DEFAULT`は許可範囲が異なります。
上記のように`ADD COLUMN`では型に合う値を指定できますが、`CREATE TABLE`の列定義では、
`DATETIME`列の`DEFAULT SYSDATE`だけを使用できます。
他の型や値を指定すると、それぞれ`ERR-02346`、`ERR-02347`で拒否されます。
作成時にデフォルト値が必要なら、先に列を作成してから`ADD COLUMN`で追加するか、入力文で値を指定してください。
配列内の一部の要素がNULLの場合とは区別してください。
列定義は括弧で囲みます。他のDBMSのALTER TABLE形式と混同しないでください。
TRANSACTIONはMODIFY COLUMNによる長さ・型の変更をサポートしていません。
必要なら、新しいスキーマへの移行手順を別途用意してください。
## 列の変更と依存オブジェクト
```sql
DROP INDEX ch8_ddl_qty;
ALTER TABLE ch8_ddl DROP COLUMN (qty);
ALTER TABLE ch8_ddl DROP COLUMN (label);
ALTER TABLE ch8_ddl DROP COLUMN (limits);
ALTER TABLE ch8_ddl RENAME COLUMN code TO product_code;
SELECT id, product_code, status FROM ch8_ddl;
SHOW INDEX ch8_ddl_code;
```
既存の行1のP-01・NEWという値と業務キーのインデックスは保持されます。
PRIMARY KEY・UNIQUE・一般・JSONパスインデックスが参照する列では、該当するインデックスを先に確認する必要があります。
最後のユーザー列は削除できません。
VIEWがテーブルや列を参照している場合、関連する名前変更・削除が拒否される場合があります。
VIEWだけでなくアプリケーションSQLとプリペアドステートメントも変更の影響を受けます。
DDL後に既存のプリペアドステートメントを無条件に再使用せず、再準備の必要性を確認してください。
```sql
ALTER TABLE ch8_ddl RENAME TO ch8_product;
SELECT id, product_code, status FROM ch8_product;
```
テーブル名の変更後は、ch8_productで検索します。
## 全件削除とテーブル削除
```sql
BEGIN;
TRUNCATE TABLE ch8_product;
SELECT COUNT(*) AS during_delete FROM ch8_product;
ROLLBACK;
SELECT COUNT(*) AS after_rollback FROM ch8_product;
DROP TABLE ch8_product;
```
件数はそれぞれ0と1です。現在のTRANSACTIONのTRUNCATEは全行削除として処理され、明示的なトランザクション内でロールバックできます。
この動作をLOG・TAGのTRUNCATEに拡大して適用しないでください。
最後のDROPは、データ・定義・関連インデックスを削除します。
## DDL運用上の注意事項
上記のTRUNCATEの動作と、CREATE・ALTER・DROPなどのスキーマ操作を区別する必要があります。
スキーマ変更をBEGIN内に置けば後でROLLBACKできるとは考えないでください。
同じテーブルのアクティブなトランザクションや開いているカーソルはDDLを妨げる場合があるため、先に結果セットと業務トランザクションを終了します。
ADD・DROP COLUMNはカタログと別の保存ファイルを併せて変更します。
処理中にサーバーが停止した場合は、再起動時の復旧が完了する前に同じDDLを繰り返さないでください。
復旧後にDESC、代表的なSELECT・INSERT、インデックス・VIEWを確認し、サーバーログも点検します。
内部保存ファイルを直接移動・変更・削除して復旧しようとしないでください。
予想と異なるスキーマが表示される場合は、変更前のDDL、実行順序、最初のエラーを併せて確認してください。
最後のエラーだけを見るより原因を特定しやすくなります。
---
title: "8.4 データ入力と変更"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/data-input-mutation/
language: ja
kind: page
---
# 8.4 データ入力と変更
UPDATEの成功応答と、注文1件が意図した状態に変わったことは別です。
条件に一致する行がなければ、エラーなしで0行が処理される場合があるためです。
変更前の対象、影響行数、変更後の値を併せて確認する習慣が必要です。
## 条件付きUPDATEとDELETE
```sql
CREATE TRANSACTION TABLE ch8_mutation (
order_id LONG PRIMARY KEY,
amount DECIMAL(18,2),
status VARCHAR(16),
ordered DATETIME
);
INSERT INTO ch8_mutation VALUES (
1001, 19900.25, 'PENDING', TO_DATE('2026-01-01', 'YYYY-MM-DD'));
INSERT INTO ch8_mutation VALUES (
1002, 29900.50, 'CANCELLED', TO_DATE('2026-01-02', 'YYYY-MM-DD'));
BEGIN;
UPDATE ch8_mutation SET status = 'SHIPPED'
WHERE order_id = 1001 AND status = 'PENDING';
SELECT order_id, status FROM ch8_mutation ORDER BY order_id;
COMMIT;
```
1001はSHIPPED、1002はCANCELLEDです。
同じUPDATEを再実行すると、PENDINGではないため影響行数は0です。
アプリケーションはSDKの影響行数を確認し、処理成功・処理済み・対象なしなどを業務規則に合わせて区別する必要があります。
次の削除も、対象件数を確認してからトランザクション内で実行します。
```sql
BEGIN;
SELECT COUNT(*) AS delete_candidates FROM ch8_mutation WHERE status = 'CANCELLED';
DELETE FROM ch8_mutation WHERE status = 'CANCELLED';
SELECT order_id, amount, status FROM ch8_mutation ORDER BY order_id;
COMMIT;
```
対象は1行で、削除後は1001の1行だけが残ります。
WHEREのないUPDATE・DELETEは全行が対象です。
運用では事前SELECTと実際の変更の間に他のセッションがデータを変更し得るため、事前件数だけを成功の根拠にしないでください。
## INSERT SELECTと自己参照
```sql
CREATE TRANSACTION TABLE ch8_archive (
order_id LONG PRIMARY KEY,
amount DECIMAL(18,2),
status VARCHAR(16),
ordered DATETIME
);
INSERT INTO ch8_archive(order_id, amount, status, ordered)
SELECT order_id, amount, status, ordered FROM ch8_mutation
WHERE ordered < TO_DATE('2026-02-01', 'YYYY-MM-DD');
INSERT INTO ch8_mutation(order_id, amount, status, ordered)
SELECT order_id + 10000, amount, status, ordered FROM ch8_mutation
WHERE order_id = 1001;
SELECT order_id FROM ch8_archive ORDER BY order_id;
SELECT order_id FROM ch8_mutation ORDER BY order_id;
```
アーカイブには1001、元テーブルには1001・11001があります。
自身のテーブルから読んだ結果を再挿入しても、この例では新しい行を無限に再入力することはありません。
ただし、キーを変えずにコピーすると一意性違反が起こり得ます。
出力先の列数と型を合わせ、コピー範囲を再実行可能な単位に分けてください。
通常の制約エラーと接続障害を同じ失敗として扱わないでください。
文の失敗はBEGIN全体を自動的にロールバックせず、コミット応答を失った場合は反映の有無を再検索する必要があります。
[トランザクション](../transaction/)で処理境界を説明します。
```sql
DROP TABLE ch8_archive;
DROP TABLE ch8_mutation;
```
## 大量取り込みとバッチ境界
TRANSACTIONもAppend APIをサポートしています。
古いファイル名やアンカーにreject・unsupportedが残っていることを理由に、現在も未サポートと判断しないでください。
言語別の公開APIは、[SDK機能のサポート範囲](/ja/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-append)を基準に選択します。
| 取り込み方式 | 確認基準 |
|---|---|
| SQL INSERT・プリペアド実行 | 文ごとのエラーと明示的トランザクション境界 |
| ドライバーのbatch | 実際の送信単位、部分成功、自動コミット |
| Append | SDKバッファ・サーバーバッチの境界、エラーコールバック・戻り値 |
| machloader | マッピングと失敗行、処理区間の記録 |
現在のSQLCLI SQLAppendBatch処理は、別のアクティブなトランザクションがなければ、サーバーバッチをトランザクションとして扱います。
この処理の制約エラーの回帰検証では、失敗したバッチ全体がロールバックされます。
これを、すべてのSDKの論理バッチ、複数回のflush、Appenderの全ライフサイクルにわたる単一のアトミック操作と解釈しないでください。
AUTO_INCREMENTとDECIMALの取り込みでは、[SQLCLIとODBC](/ja/dbms/development-tools-integration/cli-odbc/)の専用規則も確認してください。
Appendプロトコルの到着時刻フィールドが、TRANSACTIONにLOGの自動時間列を作るわけではありません。
導入前には、正常行に重複キー・NULLエラーの行を1行混ぜ、成功・失敗件数と保存結果を確認してください。
ネットワークエラー後の再送では、コミット済みデータの重複処理も考慮する必要があります。
---
title: "8.5 クエリと分析"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/query-analysis/
language: ja
kind: page
---
# 8.5 クエリと分析
クエリの構文が正しくても、入力した状態値と条件が異なれば結果は0件になります。
ソート基準が不十分だと、同時刻の行が検索ごとに異なる順序で表示される場合もあります。
さまざまな状態と境界時刻を持つサンプルで、フィルター・ソート・集計を確認します。
## 実習データの準備
```sql
CREATE TRANSACTION TABLE ch8_query (
order_id LONG PRIMARY KEY,
customer VARCHAR(32),
item_id LONG,
amount DECIMAL(18,2),
status VARCHAR(16),
ordered DATETIME
);
CREATE TRANSACTION TABLE ch8_query_product (id LONG PRIMARY KEY, name VARCHAR(64));
INSERT INTO ch8_query_product VALUES (42, 'Pump');
INSERT INTO ch8_query_product VALUES (43, 'Valve');
INSERT INTO ch8_query VALUES (
1001, 'C-01', 42, 10.25, 'PENDING', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'));
INSERT INTO ch8_query VALUES (
1002, 'C-01', 43, 20.50, 'PENDING', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'));
INSERT INTO ch8_query VALUES (
1003, 'C-02', 42, 30.75, 'SHIPPED', TO_DATE('2026-01-02', 'YYYY-MM-DD'));
SELECT order_id, amount, status FROM ch8_query WHERE order_id = 1001;
```
1001・10.25・PENDINGが返されます。
## 時間条件とソート
```sql
SELECT order_id, amount FROM ch8_query
WHERE ordered >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
AND ordered < TO_DATE('2026-01-02', 'YYYY-MM-DD')
AND status = 'PENDING'
ORDER BY ordered DESC, order_id DESC
LIMIT 1;
```
1002の1行が選択されます。orderedが同じでも、order_idで順序を固定しています。
LIMITだけを指定して意図した順序を期待しないでください。
連続する日別集計では、開始を含み終了を除く条件で境界の重複を避けられます。
LOG専用のDURATIONや自動_arrival_timeは、TRANSACTIONには適用しません。
## マスターデータとの結合
```sql
SELECT o.order_id, p.name, o.amount
FROM ch8_query o JOIN ch8_query_product p ON o.item_id = p.id
WHERE o.customer = 'C-01'
ORDER BY o.order_id;
```
結果は(1001, Pump, 10.25)、(1002, Valve, 20.50)です。
このINNER JOINでは、対応するマスターデータがない注文は除外されます。
結合先に同じキーの行が複数あると結果が増えるため、キーの一意性も確認する必要があります。
他のタイプとの結合は[JOINの実習](../join-relational-query/)で説明します。
## 集計クエリ
```sql
SELECT status, COUNT(*) AS cnt, SUM(amount) AS total_amount
FROM ch8_query GROUP BY status ORDER BY status;
```
PENDINGは2件・30.75、SHIPPEDは1件・30.75です。
インデックスがあっても、すべての集計が自動的に高速化するわけではありません。
範囲・グループ数・結果量を確認し、繰り返す業務では別途サマリーの作成を検討してください。
## JSONパスのクエリ
```sql
CREATE TRANSACTION TABLE ch8_query_json (id INTEGER PRIMARY KEY, state JSON);
INSERT INTO ch8_query_json VALUES (1, '{"status":"ALARM","score":90}');
INSERT INTO ch8_query_json VALUES (2, '{"status":"NORMAL","score":10}');
INSERT INTO ch8_query_json VALUES (3, '{"score":20}');
SELECT id, state->'$.status' AS status FROM ch8_query_json
WHERE state->'$.status' = 'ALARM'
ORDER BY id;
```
行1だけが選択されます。パスが存在しない行と、条件値が異なる行を区別してサンプルを用意してください。
矢印パスによる文字列比較と、数値抽出関数による比較を混同しないでください。
頻繁に使うパスには、[JSONパスインデックス](../index-performance/#index-strategy-rdb-json-path)を検討できます。
## インデックスと実行計画
```sql
CREATE INDEX ch8_query_status_time ON ch8_query(status, ordered);
EXPLAIN SELECT order_id FROM ch8_query
WHERE status = 'PENDING'
AND ordered >= TO_DATE('2026-01-01', 'YYYY-MM-DD');
```
複合インデックスの先頭列と条件を合わせ、実際の使用はEXPLAINで確認してください。
Machbaseがリレーショナルクエリ全体を内部SQLiteにそのまま渡すと考えると、インデックス選択や関数条件を誤解する場合があります。
```sql
DROP TABLE ch8_query_json;
DROP TABLE ch8_query_product;
DROP TABLE ch8_query;
```
結果が異なる場合は、集計やJOINを複雑に分析する前に、元の件数、WHERE条件、ソート基準を順に確認してください。
---
title: "8.6 インデックスとパフォーマンス"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/index-performance/
language: ja
kind: page
---
# 8.6 インデックスとパフォーマンス
インデックスは検索速度だけでなく、データの一意性も決定する場合があります。
業務キーを保証するインデックスと読み取り量を減らすインデックスを区別し、性能調整中に必要な制約を誤って削除しないようにします。
## インデックスの種類
| 種類 | 用途 | 複合列 | NULL |
|---|---|---|---|
| PRIMARY KEY | 行の識別。テーブルごとに1つ | 未サポート | 不可 |
| UNIQUE INDEX | 業務キーの一意性 | サポート | NULLを含むキー同士は重複ではない |
| 一般インデックス | 条件検索のアクセス経路 | サポート | 一意性検査なし |
TRANSACTIONのインデックスはBTREEと表示されます。
列のPRIMARY KEY、または作成後のCREATE PRIMARY KEY INDEXを使用できます。
LOGのLSM・KEYWORDインデックス構文を、TRANSACTIONにそのまま適用しないでください。
## UNIQUE INDEXとNULL
```sql
CREATE TRANSACTION TABLE ch8_index_account (
id LONG PRIMARY KEY,
email VARCHAR(120),
tenant INTEGER NOT NULL,
login VARCHAR(64)
);
INSERT INTO ch8_index_account VALUES (1, 'a@example.com', 1, 'alpha');
INSERT INTO ch8_index_account VALUES (2, 'b@example.com', 1, 'beta');
INSERT INTO ch8_index_account VALUES (3, NULL, 2, NULL);
INSERT INTO ch8_index_account VALUES (4, NULL, 2, NULL);
CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email);
CREATE UNIQUE INDEX ch8_index_login ON ch8_index_account(tenant, login);
SELECT id FROM ch8_index_account WHERE email IS NULL ORDER BY id;
SHOW INDEX ch8_index_email;
```
行3と4は両方存在し、インデックスも作成されます。
値が必須の業務キーでは、UNIQUEに加えて各列のNOT NULLも必要です。
CREATE TABLE内にUNIQUEを付けず、別のCREATE UNIQUE INDEXを使用してください。
次の2文は、それぞれ一意性違反を確認する任意の実習です。
```sql
-- 意図的に失敗: emailの重複
INSERT INTO ch8_index_account VALUES (5, 'a@example.com', 1, 'gamma');
UPDATE ch8_index_account SET email = 'a@example.com' WHERE id = 2;
```
失敗後も4行と、行2のb@example.comが保持される必要があります。
現在、一般的なUNIQUE違反はERR-01418として報告されます。
エラーメッセージだけでどの業務キーが重複したかを断定せず、インデックスと入力値を併せて確認してください。
## UNIQUE INDEXの削除
```sql
DROP INDEX ch8_index_email;
INSERT INTO ch8_index_account VALUES (5, 'a@example.com', 1, 'gamma');
SELECT id, email FROM ch8_index_account WHERE email = 'a@example.com' ORDER BY id;
```
これで行1と5が両方保存されます。
重複がある状態でインデックスを再作成すると失敗します。
```sql
-- 意図的に失敗: 既存データに重複があります。
CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email);
```
実習で追加した行5を削除してから、再作成します。
```sql
DELETE FROM ch8_index_account WHERE id = 5;
CREATE UNIQUE INDEX ch8_index_email ON ch8_index_account(email);
SELECT COUNT(*) AS remaining_rows FROM ch8_index_account;
```
件数は4です。
運用ではインデックスを削除する前に、性能用か一意性保証用かを確認する必要があります。
## 一般・複合インデックス
```sql
CREATE TRANSACTION TABLE ch8_index_event (
id LONG PRIMARY KEY,
status VARCHAR(16),
created DATETIME,
state JSON
);
INSERT INTO ch8_index_event VALUES (
1, 'OPEN', TO_DATE('2026-01-01', 'YYYY-MM-DD'), '{"status":"ALARM","code":500}');
INSERT INTO ch8_index_event VALUES (
2, 'CLOSED', TO_DATE('2026-01-02', 'YYYY-MM-DD'), '{"status":"NORMAL","code":200}');
INSERT INTO ch8_index_event VALUES (
3, 'OPEN', TO_DATE('2026-01-03', 'YYYY-MM-DD'), '{"code":500}');
EXPLAIN SELECT id FROM ch8_index_event
WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD');
CREATE INDEX ch8_index_status_time ON ch8_index_event(status, created);
EXPLAIN SELECT id FROM ch8_index_event
WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD');
SELECT id FROM ch8_index_event
WHERE status = 'OPEN' AND created >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
ORDER BY id;
```
結果の意味は作成前後で同じである必要があり、最後のクエリは行1と3を返します。
先頭列を条件に合わせますが、すべての複合条件が必ずそのインデックスを使用するとは断定しないでください。
Machbaseの計画選択とサポートされる条件形式をEXPLAINで確認します。
3行の実行時間は性能ベンチマークではありません。
## JSONパスインデックス
```sql
CREATE INDEX ch8_index_json_status ON ch8_index_event(state->'$.status');
CREATE INDEX ch8_index_json_code ON ch8_index_event(state->'$.code');
EXPLAIN SELECT id FROM ch8_index_event WHERE state->'$.status' = 'ALARM';
SELECT id FROM ch8_index_event WHERE state->'$.status' = 'ALARM' ORDER BY id;
SELECT id FROM ch8_index_event WHERE state->'$.code' = '500' ORDER BY id;
```
状態検索は行1、code検索は行1と3を返します。
インデックスを作成しても、すべてのJSON関数式がこの経路を使用するわけではありません。
矢印パスと数値抽出関数は、結果型と比較の意味を区別してください。
複雑な条件を頻繁に繰り返す場合は、通常の列に分離する設計も比較できます。
JSONパスのUNIQUE INDEXを作成できる場合でも、TRANSACTION UPSERTの競合選択キーには使用しません。
[UPSERTの制約](../insert-on-duplicate-key-update/)を確認してください。
## 読み取り・書き込みコスト
インデックス作成前後では、同じデータ量・条件値・同時入力レートを使用してください。
クエリ時間だけでなく、INSERT・UPDATE・DELETEのスループットとインデックス容量も比較します。
LIMITは結果量を減らしますが、返す行を固定するにはORDER BYが必要です。
```sql
DROP TABLE ch8_index_event;
DROP TABLE ch8_index_account;
```
性能のためにUNIQUE INDEXを一般インデックスに変更すると、一意性の保証は失われます。
チューニング前後で結果と制約が同じであることを、先に確認してください。
---
title: "8.7 運用とデータライフサイクル"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/operations-lifecycle/
language: ja
kind: page
---
# 8.7 運用とデータライフサイクル
古い業務データを削除するときは、日付だけの確認では不十分です。
キャンセル済みの注文と処理中の注文では保持基準が異なり、削除処理自体も他の書き込みと競合し得ます。
業務条件と処理単位を先に決めてから削除してください。
## データの保持基準
TAG・LOGには元の時系列データ、TRANSACTIONには変更可能な状態や要約結果を格納できます。
両方の保持期間が同じである必要はありません。
TRANSACTIONにはTAG・LOGのRetention Policyをそのまま適用しません。
業務条件に適したDELETEと外部ジョブスケジュールを設計してください。
## 削除とロールバック
```sql
CREATE TRANSACTION TABLE ch8_cleanup (
id LONG PRIMARY KEY,
status VARCHAR(16),
created DATETIME
);
INSERT INTO ch8_cleanup VALUES (1, 'CANCELLED', TO_DATE('2025-12-01', 'YYYY-MM-DD'));
INSERT INTO ch8_cleanup VALUES (2, 'PENDING', TO_DATE('2025-12-01', 'YYYY-MM-DD'));
INSERT INTO ch8_cleanup VALUES (3, 'CANCELLED', TO_DATE('2026-02-01', 'YYYY-MM-DD'));
BEGIN;
SELECT COUNT(*) AS delete_candidates FROM ch8_cleanup
WHERE status = 'CANCELLED' AND created < TO_DATE('2026-01-01', 'YYYY-MM-DD');
DELETE FROM ch8_cleanup
WHERE status = 'CANCELLED' AND created < TO_DATE('2026-01-01', 'YYYY-MM-DD');
SELECT id, status FROM ch8_cleanup ORDER BY id;
ROLLBACK;
SELECT COUNT(*) AS after_rollback FROM ch8_cleanup;
```
対象は1件で、削除中は行2・3、ロールバック後は3件です。
確認用の実習ではロールバックしていますが、運用で確定する場合は業務承認と結果確認後にCOMMITを選択します。
結果カーソルは終了前に閉じる必要があります。
事前の検索件数と実際の影響行数を同じものと見なさないよう注意してください。
同時変更とスナップショット競合を考慮し、実行時に得た影響行数と最終状態まで記録してください。
[ロックと再試行](../locking-conflict-timeout/)で関連する状況を確認できます。
## バッチ処理と再開
削除全体を1つの長いトランザクションで処理するより、日付区間や一意キー範囲で分割してください。
各区間の境界、処理件数、コミット結果を記録します。
途中の障害後に、どこから処理を再開するか分かる必要があります。
マスターデータの移動で、他のテーブルへコピーしてから元データを削除する場合も注意が必要です。
現在、障害時に複数のTRANSACTIONテーブルのアトミックコミットが保証されるとは考えないでください。
[トランザクションの保証範囲](../transaction/)に合わせてコピー結果の確認と再開手順を設計します。
外部API呼び出しや長いファイル処理をBEGIN内で待たないことも重要です。
## バックアップの検証
バックアップコマンドの成功だけでなく、マウントしたバックアップで業務キー・行数・合計・インデックスを点検してください。
マウントしたデータの検索には、`マウント名.所有者.テーブル名`の3部構成の名前を使用します。
2部構成の名前を使い、本番データと混同しないでください。
TRANSACTIONは、増分バックアップでもその時点のテーブルストレージ全体のスナップショットを含みます。
変更行数に比例してだけ容量が増えると計算しないでください。
具体的な実習は[バックアップ・リストア・マウント](../backup-restore-mount/)にあります。
## 削除後の運用点検
行数が減っても、OS上のファイルサイズが直ちに同じ割合で減るわけではありません。
業務データの件数、実際のファイル使用量、バックアップ保持量を個別に確認してください。
ファイルサイズを減らすために、内部SQLiteファイルへ直接接続したり、ファイルを任意に削除したりしないでください。
```sql
DROP TABLE ch8_cleanup;
```
削除処理が失敗したら、追加削除を試す前に、最後に成功した区間とコミット結果を確認してください。
これらの記録が、データの欠落と重複処理を減らすために必要です。
---
title: "8.8 制約、エラー、トラブルシューティング"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/constraints-errors-troubleshooting/
language: ja
kind: page
---
# 8.8 制約、エラー、トラブルシューティング
他のRDBMSのSQLを移行するときは、名前が似ていることを理由に同じ機能を期待しがちです。
まずEditionと公開構文を確認し、次にデータ制約と同時アクセスの問題を分けて調べてください。
## 機能のサポート範囲
TRANSACTIONはStandard Edition専用です。
ClusterではCREATE TABLE・CREATE TRANSACTION TABLE・CREATE TXN TABLEはすべて拒否されます。
LOGはCREATE LOG TABLEで明示する必要があります。
| 要求 | 対応・代替方法 |
|---|---|
| 一般的なSELECT・INSERT・UPDATE・DELETE | サポート。WHEREなしの変更は全行が対象 |
| 単一のPRIMARY KEY | サポート。テーブルごとに1つ |
| 単一・複合UNIQUE INDEX | サポート。テーブル作成後に別途作成 |
| 列の後のUNIQUE・テーブルレベルPRIMARY KEY | 該当する作成構文は未サポート |
| FOREIGN KEY・Trigger・Stored Procedure | 未サポート |
| BEGIN・COMMIT・ROLLBACK | サポート。ネストしたBEGIN・SAVEPOINTは未サポート |
| ADD・DROP・RENAME COLUMN、RENAME TO | サポート条件を確認 |
| MODIFY COLUMN | 未サポート |
| Append | SDK別の公開手段とバッチ境界を確認 |
| TAGのMETADATA・BASETIME・BASEDISTANCE | TRANSACTIONには適用しない |
Clusterで小規模なマスターデータを変更する場合はLOOKUPを検討できますが、明示的なリレーショナルトランザクションの完全な代替ではありません。
元のイベントはLOG・TAG、リレーショナルトランザクションは別のRDBMSなど、要件に応じて分ける必要があります。
## エラー別の診断
| 症状 | 確認箇所 | 次の対処 |
|---|---|---|
| ERR-01418 一意性違反 | PK・UNIQUEキーと既存データ | 入力修正またはUPSERT規則の確認 |
| NOT NULL違反 | 省略・NULL・空文字列・DEFAULT | 入力値と制約を確認 |
| UPDATEの処理が0行 | キーと現在状態の条件 | 対象なし・処理済みなどの業務状態を確認 |
| Resource busy | 他の書き込み、古い読み取りスナップショット、開いたカーソル | 原因に応じて待機・新規トランザクション・カーソル終了 |
| COMMIT・ROLLBACKがbusy | 同じ接続の開いた結果セット | 結果セットを閉じて終了を再試行 |
| エラー後の後続SQLも拒否 | ロールバック専用状態か | ROLLBACK後に新しい処理を開始 |
| DDL失敗 | 参照インデックス・VIEW・アクティブなトランザクション | 依存関係と変更タイミングを調整 |
| マウント先の値が予想と異なる | マウント名・所有者・テーブル名 | 本番データとバックアップデータを区別 |
同じResource busyでも、再試行の方法は異なります。
2接続による詳細な実習は、[ロックとbusy timeout](../locking-conflict-timeout/)を参照してください。
エラー文字列にTRANSACTIONがあることだけを理由に、繰り返し実行しないでください。
## 制約エラーとデータ保持
```sql
CREATE TRANSACTION TABLE ch8_error (
id LONG PRIMARY KEY,
code VARCHAR(32) NOT NULL,
value INTEGER
);
CREATE UNIQUE INDEX ch8_error_code ON ch8_error(code);
INSERT INTO ch8_error VALUES (1, 'A', 10);
```
以下は、それぞれ意図的に失敗する任意の実習です。
正常なSQLとまとめず、確認する文だけを実行してください。
```sql
-- PRIMARY KEYの重複
INSERT INTO ch8_error VALUES (1, 'B', 20);
-- UNIQUEの重複
INSERT INTO ch8_error VALUES (2, 'A', 20);
-- 必須値の違反
INSERT INTO ch8_error VALUES (3, NULL, 30);
-- 未サポートのスキーマ変更
ALTER TABLE ch8_error MODIFY COLUMN (code VARCHAR(64));
```
```sql
SELECT id, code, value FROM ch8_error ORDER BY id;
DROP TABLE ch8_error;
```
最後のクエリには(1, A, 10)だけが残ります。
単一文の失敗で状態が保持されることと、BEGIN内で先に成功した文まで自動的に取り消されるわけではないことを区別する必要があります。
[トランザクション](../transaction/)に比較例があります。
## 診断情報の収集
サーバーバージョン・Edition、DDLとインデックス、実行SQL、エラーコードとメッセージ全文、実際の影響行数を併せて用意してください。
接続障害では、COMMITの要求・応答時刻と業務キーも必要です。
パスワード・個人情報・機密の業務値を伏せ、再現に必要な最小限のサンプルだけを共有してください。
復旧のために内部保存ファイルを直接変更したり、本番テーブルを再作成したりしないでください。
先に原因と反映状態を確認することが、データ損失の低減につながります。
---
title: "8.9 トランザクション"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/transaction/
language: ja
kind: page
---
# 8.9 トランザクション
複数のSQLを実行中に途中の文が失敗すると、それまでの変更も消えたと考えがちです。
しかし、通常の制約エラーでは、失敗した文とトランザクション全体を区別して処理します。
この節では、同じテーブル内の変更でCOMMIT・ROLLBACKの境界を先に確認します。
## トランザクションの実行
```sql
CREATE TRANSACTION TABLE ch8_tx (
item_id LONG PRIMARY KEY,
qty INTEGER NOT NULL
);
INSERT INTO ch8_tx VALUES (1, 10);
INSERT INTO ch8_tx VALUES (2, 20);
BEGIN;
UPDATE ch8_tx SET qty = qty - 3 WHERE item_id = 1 AND qty >= 3;
UPDATE ch8_tx SET qty = qty + 3 WHERE item_id = 2;
SELECT item_id, qty FROM ch8_tx ORDER BY item_id;
ROLLBACK;
SELECT item_id, qty FROM ch8_tx ORDER BY item_id;
```
トランザクション内では7・23、ROLLBACK後は10・20が返されます。
アプリケーションは、2つのUPDATEがそれぞれ想定した1行を処理したことを確認する必要があります。
条件不一致で更新が0行になるのはSQLエラーではないため、データベースが業務失敗を自動判定することはありません。
次は同じ変更を確定する通常の実習です。
```sql
BEGIN;
UPDATE ch8_tx SET qty = qty - 3 WHERE item_id = 1 AND qty >= 3;
UPDATE ch8_tx SET qty = qty + 3 WHERE item_id = 2;
COMMIT;
SELECT item_id, qty FROM ch8_tx ORDER BY item_id;
```
確定後の値は7・23です。
公開構文はBEGINであり、BEGIN TRANSACTION、ネストしたBEGIN、SAVEPOINTはサポートしていません。
明示的なトランザクションがなければ、TRANSACTIONのDMLは文単位で処理されます。
ドライバーの自動コミット・トランザクションAPIは別途確認してください。
## 文のエラーとロールバック
次はエラー処理を学ぶための流れです。重複INSERTは意図的に失敗します。
SQL実行ツールがエラーで停止した場合は、必ず同じ接続でROLLBACKまで実行してください。
```sql
BEGIN;
UPDATE ch8_tx SET qty = 100 WHERE item_id = 1;
```
```sql
-- 意図的に失敗: item_idの重複
INSERT INTO ch8_tx VALUES (1, 999);
```
```sql
SELECT item_id, qty FROM ch8_tx ORDER BY item_id;
ROLLBACK;
SELECT item_id, qty FROM ch8_tx ORDER BY item_id;
```
最初の検索結果は100・23、ROLLBACK後は7・23です。
通常の制約エラーで失敗した文が取り消されても、先に成功した文はトランザクション内に残ります。
業務全体を取り消すには、アプリケーションがROLLBACKを選ぶ必要があります。
すべてのエラー後に続行できるわけではありません。復旧処理でロールバック専用状態になった場合は、ROLLBACKで終了する必要があります。
## TRUNCATEとロールバック
```sql
BEGIN;
TRUNCATE TABLE ch8_tx;
SELECT COUNT(*) AS during_truncate FROM ch8_tx;
ROLLBACK;
SELECT COUNT(*) AS after_rollback FROM ch8_tx;
```
結果は0と2です。
現在のTRANSACTIONのTRUNCATEは全行削除として、明示的トランザクションに含まれます。
LOG・TAGのデータ削除や、CREATE・ALTER・DROPなどのスキーマ変更と混同しないでください。
スキーマ操作は業務トランザクションの外で行うことが運用基準です。
## テーブルタイプ別のトランザクション範囲
アクティブなTRANSACTIONトランザクション内でも、LOG・TAG・LOOKUP・VOLATILEの検索と混合結合は許可されます。
一方、これらのタイプへの書き込みを同じトランザクションにまとめることはできません。
検索が許可されても、そのタイプがTRANSACTIONと同じスナップショット・ロールバック保証を得るわけではありません。
元データの収集と業務状態の変更の間の整合性は、別途設計してください。
TRANSACTIONテーブルの読み取りには、他のセッションの未コミット変更が見えないスナップショットを使用します。
BEGIN呼び出し時に、すべてのテーブルで共通の読み取り時点が一括で固定されるとは考えないでください。
読み取りから書き込みへの移行時の競合は、[ロックと再試行](../locking-conflict-timeout/)で説明します。
## 複数テーブルのコミットと障害
複数のTRANSACTIONテーブルのDMLをBEGINでまとめ、通常どおりCOMMIT・ROLLBACKすることはできます。
ただし、現在のストレージはテーブルごとにハンドルを使用し、COMMITもハンドルごとに順次処理します。
したがって、コミット中に障害が発生しても、複数テーブル全体が必ず一緒に確定または取り消されるアトミックコミットを保証すると解釈しないでください。
複数テーブルの不可分な処理が必須の業務では、この制限を先に検討してください。
コミット失敗や応答消失後にROLLBACKを送信したことだけで、すべてのテーブルが元に戻ったと判断せず、
業務キーで反映状態を再確認する必要があります。
この節の基本実習を1つのテーブルの2行で構成したのも、このためです。
## カーソルとトランザクション終了
開いているTRANSACTIONカーソルがある場合、COMMIT・ROLLBACKがResource busyで失敗することがあります。
SDKの結果セット・ステートメントを終了してから、終了文を再実行してください。
接続終了時に未コミット変更はロールバックされますが、接続を失う前にサーバーですでにコミットされたかどうかは、クライアントが別途確認する必要があります。
```sql
DROP TABLE ch8_tx;
```
BEGIN内で外部API呼び出しや長い計算を待たないでください。
トランザクションを短く保ち、失敗時に再実行するのか、先に結果を確認するのかを区別すると、運用中の判断が明確になります。
---
title: "8.10 ロック、競合、busy timeout"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/locking-conflict-timeout/
language: ja
kind: page
---
# 8.10 ロック、競合、busy timeout
別々の行を変更しているのにResource busyが発生する場合、行ロックだけを考えると原因を特定しにくくなります。
TRANSACTIONの書き込み競合は、同じテーブルの異なる行の間でも発生し得ます。
待てば解消する競合と、トランザクションを再開始する必要がある競合を区別します。
## 実習環境
この実習は、デフォルトのWAL設定を使用する検証用Standard環境を対象とします。
A・Bは同じアカウント・データベースに接続した別々の接続です。
各コードブロックを示した順に実行し、SELECT結果は最後まで読み取ってカーソルを閉じてください。
スナップショット実習のために、本番サーバーのジャーナルモードを変更しないでください。
Aで準備します。
```sql
SELECT NAME, VALUE FROM V$PROPERTY WHERE NAME = 'TRANSACTION_JOURNAL_MODE';
CREATE TRANSACTION TABLE ch8_lock (id INTEGER PRIMARY KEY, val INTEGER);
INSERT INTO ch8_lock VALUES (1, 10);
INSERT INTO ch8_lock VALUES (2, 20);
```
TRANSACTION_JOURNAL_MODE=4がWALです。
他の値の場合は、次のWALスナップショット実習と同じ結果を期待せず、環境を先に確認してください。
## 同時書き込みの競合
Aでトランザクションを開始し、終了せずに待ちます。
```sql
BEGIN;
UPDATE ch8_lock SET val = 11 WHERE id = 1;
```
続いてBで検索します。実習用のB接続だけ、待機時間を0に変更します。
```sql
ALTER SESSION SET TRANSACTION_BUSY_TIMEOUT_MS = 0;
SELECT id, val FROM ch8_lock ORDER BY id;
```
Bには、Aの未コミット値11ではなく、既存値10・20が見えます。
次のBのUPDATEは、意図的にResource busyエラーを発生させる段階です。
```sql
-- B: Aとは異なる行でも、同じテーブルへの書き込みのため失敗が想定されます。
UPDATE ch8_lock SET val = val + 1 WHERE id = 2;
```
AでCOMMITしてから、BのUPDATEを再実行します。
```sql
-- A
COMMIT;
```
```sql
-- B
UPDATE ch8_lock SET val = val + 1 WHERE id = 2;
SELECT id, val FROM ch8_lock ORDER BY id;
```
値は11・21になります。
これは、同じテーブルの書き込み競合を一般的な行単位ロックと解釈してはいけないことを示します。
## WALスナップショット競合
前の手順がすべて完了したら、Aで読み取りトランザクションを開始します。
```sql
-- A
BEGIN;
SELECT val FROM ch8_lock WHERE id = 1;
```
Aが11を読み取った後、Bで値を変更します。Bには明示的なトランザクションがない状態です。
```sql
-- B
UPDATE ch8_lock SET val = val + 10 WHERE id = 1;
```
続いてAが書き込みに移行すると、スナップショット競合が想定されます。
```sql
-- A: 意図的に失敗する段階
UPDATE ch8_lock SET val = val + 1 WHERE id = 1;
```
別の接続がすでにコミットしたため、Aの古い読み取りスナップショットをそのまま書き込みに移行できません。
現在、この競合はbusy timeoutを延長したり-1に設定したりしても、待機では解決しません。
同じUPDATEだけを繰り返さず、Aのトランザクションを終了して新しい状態で再判断します。
```sql
-- A
ROLLBACK;
BEGIN;
UPDATE ch8_lock SET val = val + 1 WHERE id = 1;
COMMIT;
SELECT id, val FROM ch8_lock ORDER BY id;
```
最終値は22・21です。
業務で読み取った値を使って次の変更を計算した場合は、新しいトランザクションで読み取りと判断からやり直す必要があります。
## busy timeout
サーバーのデフォルトのTRANSACTION_BUSY_TIMEOUT_MSは30000msで、新しいセッションにコピーされます。
現在のセッションではALTER SESSIONで変更できます。
| 値 | 一時的なロック競合の処理 |
|---|---|
| -1 | キャンセル・接続終了またはロック解放まで待機 |
| 0 | 待機せずbusyを返す |
| 正数 | 指定ミリ秒の範囲内で待機し、処理するかbusyを返す |
スナップショット移行競合のように、再試行で解消できない場合はこのポリシーの例外です。
-1をすべての競合に対する無限再試行と解釈しないでください。
DDL_LOCK_TIMEOUTは別のDDLロック待機設定で、変更してもスナップショット競合は解決しません。
## エラーと再試行
メッセージにTRANSACTIONがあることだけで再試行すると、型・制約・権限エラーまで繰り返してしまいます。
ドライバーのエラーコード、診断全文、操作の種類を併せて確認し、再試行可能なロック競合かを区別してください。
明示的なトランザクションで再試行するには、開いている結果セットを閉じてROLLBACKした後、
回数と要求全体の時間に上限を設け、新しいトランザクションで再実行します。
接続消失やCOMMIT応答の消失は別のケースです。
業務キーで処理済みかを確認せず、カウンター増加や注文処理を再実行すると、重複して反映される場合があります。
## 競合の診断
```sql
SELECT id, user_name, user_ip, transaction_busy_timeout_ms
FROM V$SESSION WHERE closed = 0 ORDER BY id;
SELECT id, sess_id, state, query FROM V$STMT
WHERE state LIKE 'Execute in progress%'
OR state LIKE 'Fetch in progress%';
```
このクエリはロック所有者を直接対応付けるものではありません。
V$MUTEXもサーバー内部のミューテックス統計であり、業務行のロック一覧ではありません。
接続情報とアプリケーションのBEGIN・終了記録を併せて確認してください。
セッションの強制終了は未コミット業務を取り消す場合があるため、最初の対処にはしないでください。
両方の接続に開いたトランザクションがないことを確認してから、Aでクリーンアップします。
```sql
DROP TABLE ch8_lock;
```
実習用接続A・Bを終了すると、Bに指定したセッション単位のtimeoutも影響しなくなります。
運用では、外部API呼び出しや長い計算をBEGINの外へ移すだけでも、待機の原因を減らせます。
---
title: "8.11 JOINとリレーショナルクエリの設計"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/join-relational-query/
language: ja
kind: page
---
# 8.11 JOINとリレーショナルクエリの設計
JOINを追加して注文件数が減少・増加した場合は、まず関係の形を確認する必要があります。
INNER JOINは対応する行がない行を除外し、1件に複数の行が一致すると結果を増やします。
SQLがエラーなしで実行されることと、業務件数を正しく集計することは別です。
## TRANSACTION–LOOKUP結合
```sql
CREATE TRANSACTION TABLE ch8_join_order (
order_id LONG PRIMARY KEY,
item_id LONG,
qty INTEGER
);
CREATE LOOKUP TABLE ch8_join_product (id LONG PRIMARY KEY, name VARCHAR(64));
CREATE TRANSACTION TABLE ch8_join_payment (order_id LONG PRIMARY KEY, status VARCHAR(16));
INSERT INTO ch8_join_order VALUES (1, 42, 2);
INSERT INTO ch8_join_order VALUES (2, 99, 1);
INSERT INTO ch8_join_product VALUES (42, 'Pump');
INSERT INTO ch8_join_payment VALUES (1, 'PAID');
SELECT o.order_id, p.name, o.qty
FROM ch8_join_order o JOIN ch8_join_product p ON o.item_id = p.id
ORDER BY o.order_id;
SELECT o.order_id, p.name, o.qty
FROM ch8_join_order o LEFT JOIN ch8_join_product p ON o.item_id = p.id
ORDER BY o.order_id;
```
INNER JOINは注文1だけ、LEFT JOINは注文1・2を返します。
注文2の製品名はNULLです。製品99が存在しなくても、注文の入力自体は外部キーで拒否されないため、必要な参照検証は別途設計する必要があります。
LEFT JOIN後に右側テーブルの条件をWHEREに指定しないよう注意してください。
例えば`WHERE p.name = 'Pump'`を追加すると、NULL行が除外されます。
結合先を探す条件なのか、最終結果をフィルタリングする条件なのかを区別してください。
## TRANSACTION間の結合
```sql
SELECT o.order_id, o.qty, p.status
FROM ch8_join_order o
JOIN ch8_join_payment p ON o.order_id = p.order_id
ORDER BY o.order_id;
```
(1, 2, PAID)の1行が返されます。
実際の支払い履歴が注文ごとに複数行あれば、この結果も複数行になります。
結合後に注文金額を合計するとき、重複集計を避けるために関係と集計単位を確認してください。
## TAGの近接時刻結合
次は、アラームの前後5秒以内にあるすべての測定値を結合する例です。
```sql
CREATE TRANSACTION TABLE ch8_join_alarm (
alarm_id LONG PRIMARY KEY,
sensor VARCHAR(32),
occurred DATETIME
);
CREATE TAG TABLE ch8_join_sensor (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
INSERT INTO ch8_join_alarm VALUES (
1, 'TEMP-01', TO_DATE('2026-01-01 10:00:05', 'YYYY-MM-DD HH24:MI:SS'));
INSERT INTO ch8_join_sensor VALUES (
'TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 10);
INSERT INTO ch8_join_sensor VALUES (
'TEMP-01', TO_DATE('2026-01-01 10:00:10', 'YYYY-MM-DD HH24:MI:SS'), 20);
INSERT INTO ch8_join_sensor VALUES (
'TEMP-01', TO_DATE('2026-01-01 10:00:11', 'YYYY-MM-DD HH24:MI:SS'), 30);
SELECT a.alarm_id, s.time, s.value
FROM ch8_join_alarm a JOIN ch8_join_sensor s ON a.sensor = s.name
WHERE s.time >= a.occurred - 5s
AND s.time <= a.occurred + 5s
ORDER BY a.alarm_id, s.time;
```
アラーム1に値10・20の2行が結合されます。両側の境界を含み、値30は除外されます。
このクエリは最も近い測定値1つや、完全に同じ時刻の値を選ぶ機能ではありません。
1つの値だけが必要なら、直前値・最短距離などの選択基準と同順位の処理規則を別途定めてください。
## 結合の設計基準
結合キーの型と値の形式を合わせ、時間範囲を制限してから実行計画を確認します。
必要な列だけを返し、結合キーへの不用意な関数・型変換の追加でアクセス経路が変わらないか比較してください。
結合順序やアルゴリズムが他のRDBMSと同じだと考えないでください。
混合結合が許可されても、他のテーブルタイプがTRANSACTIONと同じトランザクションスナップショットを共有するわけではありません。
また、現在のLOOKUPの説明を付加しても、過去の時点の説明までは再現しません。
```sql
DROP TABLE ch8_join_sensor;
DROP TABLE ch8_join_alarm;
DROP TABLE ch8_join_payment;
DROP TABLE ch8_join_product;
DROP TABLE ch8_join_order;
```
結果件数が一致しない場合は、結合前の件数とキーごとの結合先行数を先に比較してください。
この2つが確認できると、クエリの修正方法も明確になります。
---
title: "8.12 TRANSACTIONのバックアップ、リストア、マウント"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/backup-restore-mount/
language: ja
kind: page
---
# 8.12 TRANSACTIONのバックアップ、リストア、マウント
バックアップコマンドに成功しても、復旧の準備が完了したとは限りません。
特に本番テーブルとバックアップテーブルが同名だと、誤った方を検索して検証完了と考えがちです。
バックアップ後に本番の値を変更し、両方の結果が異なることを確認する方法で検証します。
## バックアップ・リストアのサポート範囲
| 操作 | TRANSACTIONに関する基準 |
|---|---|
| BACKUP DATABASE | 対象範囲の永続的なTRANSACTIONデータを含む |
| BACKUP TABLE | 指定テーブルと必要なメタデータをバックアップ |
| 増分バックアップ | TRANSACTIONストレージは、その時点の全体スナップショットとして含まれる |
| MOUNT DATABASE | バックアップを読み取り専用で検索 |
| オフラインインスタンス復旧 | サーバーを停止しmachadmin -rを使用 |
| オンライン論理データベース復旧 | サポートされる論理バックアップをRESTORE DATABASEで復元 |
増分バックアップのTRANSACTIONデータを、変更行だけの差分として見積もらないでください。
内部ファイルの直接コピーではなく、サポートされるバックアップコマンドを使用する必要があります。
TRANSACTIONを含むバックアップを、Clusterで使用するための迂回手段にすることもできません。
## バックアップとマウントの検証
この実習は、検証用Standard環境のSYSアカウントを対象にします。
バックアップ・マウント権限と、サーバーファイルへのアクセス権限が必要です。
パスはサーバー上の例であり、実行するたびに存在しない新しいパスに変更してください。
親ディレクトリと空き容量を確認し、パスを再使用するために既存のバックアップを削除しないでください。
```sql
CREATE TRANSACTION TABLE ch8_backup (
id LONG PRIMARY KEY,
code VARCHAR(32) NOT NULL,
amount DECIMAL(18,2)
);
CREATE UNIQUE INDEX ch8_backup_code ON ch8_backup(code);
INSERT INTO ch8_backup VALUES (1, 'A', 10.25);
INSERT INTO ch8_backup VALUES (2, 'B', 20.50);
BACKUP TABLE ch8_backup INTO DISK = '/backup/ch8_table_20260907_a';
UPDATE ch8_backup SET amount = 99.00 WHERE id = 1;
MOUNT DATABASE '/backup/ch8_table_20260907_a' TO ch8_bak;
SELECT id, code, amount FROM ch8_bak.SYS.ch8_backup ORDER BY id;
SELECT id, code, amount FROM ch8_backup ORDER BY id;
```
バックアップ側は10.25・20.50、本番側は99.00・20.50です。
マウントしたデータの検索には、`マウント名.所有者.テーブル名`の3部構成の名前を使用します。
別の所有アカウントで実習した場合は、SYSも実際の所有者に合わせる必要があります。
`SELECT ... FROM ch8_backup`だけを実行しないよう注意してください。
これはマウントしたバックアップの検証ではなく、現在の接続の本番テーブルを検索します。
バックアップに含めなかった他のテーブルも存在するはずだと期待しないでください。
マウントは読み取り専用であり、UPDATE・DDLを行う復旧環境ではありません。
検証を終え、開いているカーソルを閉じてからマウントを解除します。
```sql
UMOUNT DATABASE ch8_bak;
DROP TABLE ch8_backup;
```
このクリーンアップは、実習テーブルとマウントだけを削除します。
バックアップディレクトリは残るため、以後の保持ポリシーに従って別途管理してください。
## リストアの検証項目
隔離した復旧環境では、所有者、行数、業務キー、金額合計、代表的なJSON値を確認してください。
PRIMARY KEY・UNIQUE INDEXが残っているか、必要な権限とアプリケーションのCOMMIT・ROLLBACKの流れが正常かも点検します。
マウント検索だけでは、実際の書き込み復旧の検証まで完了したことにはなりません。
オンラインRESTORE DATABASEは、論理バックアップと対象データベースの条件に従います。
複数のデータベースを含むインスタンス全体のイメージと混同しないでください。
既存インスタンスを削除するオフライン復旧やREPLACEは、この実習には含めません。
[リストア構文](/ja/dbms/reference/sql/syntax/backup-restore-mount-syntax/)と
[運用手順](/ja/dbms/operations-configuration-recovery/backup-restore-mount/)で、
権限・停止・対象置換の条件を確認してから別途実行してください。
複数テーブルの業務整合性まで検証する場合は、バックアップコマンドの成功だけで判断しないでください。
書き込み停止・業務の基準時点と、テーブル間の検証基準を併せて定めることを推奨します。
---
title: "8.13 TRANSACTION INSERT ON DUPLICATE KEY UPDATE"
url: https://docs.machbase.com/ja/dbms/rdb-table-usage/insert-on-duplicate-key-update/
language: ja
kind: page
---
# 8.13 TRANSACTION INSERT ON DUPLICATE KEY UPDATE
「なければ追加し、あれば更新する」操作は単純に見えますが、何を重複と見なすかによって更新される行が変わります。
特にカウンター増加を再送すると、同じイベントが2回反映される場合があります。
キー、更新対象、再試行ポリシーを併せて確認してください。
TRANSACTIONの`INSERT ... ON DUPLICATE KEY UPDATE`は、PRIMARY KEYまたは一般のUNIQUE INDEXの競合時に既存行を更新します。
次の実習は、このページ内で必要なオブジェクトを準備します。
エラー確認SQLは通常の流れと分離し、最後のクリーンアップまで実行してから再実行してください。
## サポートする構文
TRANSACTIONテーブルでは、`INSERT ... VALUES ...`形式のUPSERTをサポートします。
```text
INSERT INTO table_name VALUES (...)
ON DUPLICATE KEY UPDATE;
INSERT INTO table_name VALUES (...)
ON DUPLICATE KEY UPDATE SET column_name = expression [, ...];
INSERT INTO table_name(column_name, ...)
VALUES (...)
ON DUPLICATE KEY UPDATE;
INSERT INTO table_name(column_name, ...)
VALUES (...)
ON DUPLICATE KEY UPDATE SET column_name = expression [, ...];
```
競合判定キーとして認められる対象は次のとおりです。
- TRANSACTION PRIMARY KEY
- TRANSACTION UNIQUE INDEX
- TRANSACTION複合UNIQUE INDEX
## 基本動作
重複がなければ、通常のINSERTと同様に新しい行を追加します。
```sql
CREATE TRANSACTION TABLE ch8_up_device_state (
device_id INTEGER PRIMARY KEY,
status VARCHAR(16),
alarm_count INTEGER,
updated_at DATETIME
);
INSERT INTO ch8_up_device_state
VALUES (1, 'NORMAL', 0, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET
status = 'NORMAL',
updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS');
```
PRIMARY KEYが重複すると、既存行をUPDATEします。
```sql
INSERT INTO ch8_up_device_state
VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET
status = 'ALARM',
alarm_count = alarm_count + 1,
updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS');
```
`SET`句ではPRIMARY KEYを変更できません。右辺の式は競合した既存行を基準に評価します。
したがって、`alarm_count = alarm_count + 1`は挿入しようとした値ではなく、既存行のalarm_countに1を加算します。
```sql
SELECT device_id, status, alarm_count, updated_at
FROM ch8_up_device_state
WHERE device_id = 1;
```
想定する結果形式は次のとおりです。
```text
DEVICE_ID STATUS ALARM_COUNT UPDATED_AT
--------- ------ ----------- -----------------------------
1 ALARM 1 2026-07-10 09:05:00 000:000:000
```
`ON DUPLICATE KEY UPDATE`の後の`SET`句は省略できます。
```sql
CREATE TRANSACTION TABLE ch8_up_asset_cache (
asset_id INTEGER PRIMARY KEY,
asset_name VARCHAR(80),
location VARCHAR(80),
keep_value INTEGER
);
INSERT INTO ch8_up_asset_cache VALUES (1, 'compressor-a', 'plant-1', 100);
INSERT INTO ch8_up_asset_cache(asset_id, asset_name, location)
VALUES (1, 'compressor-a-renamed', 'plant-2')
ON DUPLICATE KEY UPDATE;
```
`SET`句がない場合は、INSERT対象列のうちPRIMARY KEY以外の列だけを既存行に反映します。
上の例では`asset_name`、`location`が更新され、列リストにない`keep_value`は既存値を保持します。
```sql
SELECT asset_id, asset_name, location, keep_value
FROM ch8_up_asset_cache
ORDER BY asset_id;
```
想定する結果形式は次のとおりです。
```text
ASSET_ID ASSET_NAME LOCATION KEEP_VALUE
-------- -------------------- -------- ----------
1 compressor-a-renamed plant-2 100
```
PRIMARY KEY列だけのテーブルで、重複行に`SET`なしのUPSERTを実行すると、更新対象列がないため行は変更されません。
## UNIQUE INDEXの重複処理
PRIMARY KEYだけでなく、UNIQUE INDEXの競合でも更新処理が実行されます。
```sql
CREATE TRANSACTION TABLE ch8_up_account_profile (
id INTEGER PRIMARY KEY,
email VARCHAR(120),
display_name VARCHAR(80),
login_count INTEGER
);
CREATE UNIQUE INDEX ch8_up_uidx_account_profile_email
ON ch8_up_account_profile(email);
INSERT INTO ch8_up_account_profile
VALUES (1, 'ops@example.com', 'ops-user', 1);
INSERT INTO ch8_up_account_profile
VALUES (2, 'ops@example.com', 'ops-renamed', 1)
ON DUPLICATE KEY UPDATE SET
display_name = 'ops-renamed',
login_count = login_count + 1;
SELECT id, email, display_name, login_count
FROM ch8_up_account_profile
ORDER BY id;
```
`email`のUNIQUE INDEXが重複するため、`id = 1`の行がUPDATEされます。
挿入しようとした`id = 2`の行は新規追加されません。
複合UNIQUE INDEXは、キーの組み合わせ全体が同じ場合に重複として処理します。
```sql
CREATE TRANSACTION TABLE ch8_up_daily_device_summary (
id INTEGER PRIMARY KEY,
device_id INTEGER,
summary_day VARCHAR(10),
event_count INTEGER,
last_status VARCHAR(16)
);
CREATE UNIQUE INDEX ch8_up_uidx_daily_device_summary
ON ch8_up_daily_device_summary(device_id, summary_day);
INSERT INTO ch8_up_daily_device_summary
VALUES (1, 101, '2026-07-10', 3, 'NORMAL');
INSERT INTO ch8_up_daily_device_summary
VALUES (2, 101, '2026-07-10', 1, 'ALARM')
ON DUPLICATE KEY UPDATE SET
event_count = event_count + 1,
last_status = 'ALARM';
INSERT INTO ch8_up_daily_device_summary
VALUES (3, 101, '2026-07-11', 1, 'NORMAL')
ON DUPLICATE KEY UPDATE SET
event_count = event_count + 1;
```
最初のUPSERTは`(device_id, summary_day) = (101, '2026-07-10')`の行をUPDATEします。
2番目のUPSERTは日付が異なるため、新しい行をINSERTします。
UNIQUE KEYにNULLを含む行同士は、重複として処理しません。
次の2つの入力は互いを上書きせず、それぞれ新しい行になります。
```sql
INSERT INTO ch8_up_daily_device_summary VALUES (4, NULL, '2026-07-10', 1, 'NORMAL')
ON DUPLICATE KEY UPDATE;
INSERT INTO ch8_up_daily_device_summary VALUES (5, NULL, '2026-07-10', 2, 'ALARM')
ON DUPLICATE KEY UPDATE;
SELECT id, device_id, summary_day, event_count
FROM ch8_up_daily_device_summary ORDER BY id;
```
結果のidは1・3・4・5、event_countはそれぞれ4・1・1・2です。
必須の業務キーでは、UNIQUE INDEXに加えて構成列のNOT NULLも必要です。
## 活用例
TAGテーブルに時系列の測定値を継続的に蓄積し、TRANSACTIONテーブルに機器別の最新状態だけを維持できます。
```sql
CREATE TRANSACTION TABLE ch8_up_latest_device_status (
device_name VARCHAR(80) PRIMARY KEY,
last_value DOUBLE,
last_state VARCHAR(16),
event_count LONG,
updated_at DATETIME
);
INSERT INTO ch8_up_latest_device_status
VALUES ('compressor-a', 72.5, 'NORMAL', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET
last_value = 72.5,
last_state = 'NORMAL',
event_count = event_count + 1,
updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS');
INSERT INTO ch8_up_latest_device_status
VALUES ('compressor-a', 91.2, 'ALARM', 1, TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET
last_value = 91.2,
last_state = 'ALARM',
event_count = event_count + 1,
updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS');
```
このパターンは、ダッシュボードが最新状態だけを高速に検索する場合に使用できます。
外部システムが同じ業務キーでマスターデータを繰り返し送信する場合は、UNIQUE INDEXを基準にUPSERTできます。
```sql
CREATE TRANSACTION TABLE ch8_up_customer_device (
id LONG PRIMARY KEY AUTO_INCREMENT,
external_device_id VARCHAR(64),
device_name VARCHAR(80),
owner_name VARCHAR(80),
enabled INTEGER
);
CREATE UNIQUE INDEX ch8_up_uidx_customer_device_external_id
ON ch8_up_customer_device(external_device_id);
INSERT INTO ch8_up_customer_device(external_device_id, device_name, owner_name, enabled)
VALUES ('ERP-DEV-10001', 'compressor-a', 'line-1', 1)
ON DUPLICATE KEY UPDATE SET
device_name = 'compressor-a',
owner_name = 'line-1',
enabled = 1;
INSERT INTO ch8_up_customer_device(external_device_id, device_name, owner_name, enabled)
VALUES ('ERP-DEV-10001', 'compressor-a-renamed', 'line-2', 1)
ON DUPLICATE KEY UPDATE SET
device_name = 'compressor-a-renamed',
owner_name = 'line-2',
enabled = 1;
```
最初のINSERTは新しい行を作成し、2番目のINSERTは`external_device_id`のUNIQUE INDEX競合によって既存行をUPDATEします。
内部の`id`は保持されます。
ソースデータの列値をそのまま最新キャッシュに反映する場合は、`SET`句なしのUPSERTを使用できます。
```sql
CREATE TRANSACTION TABLE ch8_up_tag_alias_cache (
alias_name VARCHAR(80) PRIMARY KEY,
tag_name VARCHAR(80),
unit VARCHAR(16),
description VARCHAR(160),
manually_checked INTEGER
);
INSERT INTO ch8_up_tag_alias_cache
VALUES ('compressor-a-temp', 'comp_a.temp', 'celsius', 'main compressor temp', 1);
INSERT INTO ch8_up_tag_alias_cache(alias_name, tag_name, unit, description)
VALUES ('compressor-a-temp', 'comp_a.temperature', 'celsius', 'renamed tag')
ON DUPLICATE KEY UPDATE;
```
上の文は`tag_name`、`unit`、`description`だけを更新します。
列リストにない`manually_checked`は既存値を保持します。
集計テーブルでキーごとの発生回数を累積できます。
```sql
CREATE TRANSACTION TABLE ch8_up_alarm_counter (
alarm_code VARCHAR(32) PRIMARY KEY,
first_seen DATETIME,
last_seen DATETIME,
hit_count LONG
);
INSERT INTO ch8_up_alarm_counter
VALUES (
'OVER_TEMP',
TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),
TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),
1
)
ON DUPLICATE KEY UPDATE SET
last_seen = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),
hit_count = hit_count + 1;
INSERT INTO ch8_up_alarm_counter
VALUES (
'OVER_TEMP',
TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'),
TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'),
1
)
ON DUPLICATE KEY UPDATE SET
last_seen = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS'),
hit_count = hit_count + 1;
```
`hit_count = hit_count + 1`は既存行を基準に計算するため、累積カウンターに使用できます。
JSON列も更新対象列として使用できます。
```sql
CREATE TRANSACTION TABLE ch8_up_device_json_state (
device_id INTEGER PRIMARY KEY,
state JSON,
updated_at DATETIME
);
INSERT INTO ch8_up_device_json_state
VALUES (
1,
'{"status":"NORMAL","score":10}',
TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS')
)
ON DUPLICATE KEY UPDATE SET
state = '{"status":"NORMAL","score":10}',
updated_at = TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS');
INSERT INTO ch8_up_device_json_state
VALUES (
1,
'{"status":"ALARM","score":90}',
TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS')
)
ON DUPLICATE KEY UPDATE SET
state = '{"status":"ALARM","score":90}',
updated_at = TO_DATE('2026-07-10 09:05:00', 'YYYY-MM-DD HH24:MI:SS');
SELECT JSON_EXTRACT_STRING(state, '$.status') AS status,
JSON_EXTRACT_INTEGER(state, '$.score') AS score
FROM ch8_up_device_json_state
WHERE device_id = 1;
```
制限: JSONパスのUNIQUE INDEXは、競合判定キー候補から除外されます。
JSONパスのUNIQUE INDEX競合はUPSERTの更新処理に切り替わらず、一意性制約エラーとして処理されます。
## トランザクションと権限
TRANSACTIONのUPSERTは、通常のINSERT/UPDATEと同様にトランザクション内でCOMMITまたはROLLBACKされます。
```sql
CREATE TRANSACTION TABLE ch8_up_tx_device_state (
id INTEGER PRIMARY KEY,
status VARCHAR(16),
count_value INTEGER
);
INSERT INTO ch8_up_tx_device_state VALUES (1, 'NORMAL', 10);
BEGIN;
INSERT INTO ch8_up_tx_device_state VALUES (2, 'NORMAL', 1)
ON DUPLICATE KEY UPDATE SET count_value = count_value + 1;
INSERT INTO ch8_up_tx_device_state VALUES (1, 'ALARM', 1)
ON DUPLICATE KEY UPDATE SET
status = 'ALARM',
count_value = count_value + 1;
ROLLBACK;
SELECT id, status, count_value
FROM ch8_up_tx_device_state
ORDER BY id;
```
上の例では、挿入処理と更新処理の両方がROLLBACKされます。
通常の制約違反で重複更新文が失敗しても、明示的トランザクション内で先に成功した変更は残る場合があります。
アプリケーションはエラーを確認して後続処理を決めるか、ROLLBACKで業務変更を取り消す必要があります。
TRANSACTIONのUPSERT文には、`INSERT`権限と`UPDATE`権限の両方が必要です。
実行結果が挿入処理であっても、文に更新処理が含まれるため両方の権限を付与する必要があります。
次は権限の形式だけを示す例です。
実際の所有者・テーブル・既存アプリケーションアカウントに合わせ、別の管理作業として適用してください。
```text
GRANT INSERT ON owner.table_name TO app_user;
GRANT UPDATE ON owner.table_name TO app_user;
```
`SELECT`権限は、TRANSACTIONのUPSERT文の実行自体には不要です。
ただし、アプリケーションが結果確認のために`SELECT`を実行する場合は、別途`SELECT`権限が必要です。
## サポートする型と制約
`SET`句で更新できる列の型は、通常のTRANSACTION `UPDATE`と同じ公開型のサポート範囲に従います。
| 分類 | 型 |
| --- | --- |
| 整数 | `SHORT`, `INT16`, `USHORT`, `UINT16`, `INT`, `INTEGER`, `INT32`, `UINTEGER`, `UINT32`, `LONG`, `INT64`, `ULONG`, `UINT64` |
| 浮動小数点 | `FLOAT`, `DOUBLE` |
| 固定小数点 | `DECIMAL`, `NUMERIC`, `DEC`, `FIXED`, `NUMBER` |
| 文字列/LOB | `VARCHAR`, `TEXT`, `CLOB`, `BINARY`, `BLOB` |
| その他 | `DATETIME`, `IPV4`, `IPV6`, `JSON` |
上の表は、TRANSACTIONで使用するスカラー型をまとめたものです。
数値ARRAYのサポート範囲は、[データ型リファレンス](/ja/dbms/reference/sql/types/)を参照してください。
競合判定キーとなるキー・インデックスの型は、TRANSACTION PRIMARY KEYとUNIQUE INDEXの型ポリシーに従います。
この機能はキー型のサポート範囲を拡張しません。
次の構文はサポートしていません。
```text
-- 未サポートの構文を示す説明用のブロックです。
-- INSERT SELECTとON DUPLICATE KEY UPDATEの組み合わせは未サポートです。
INSERT INTO ch8_up_device_state(device_id, status, alarm_count, updated_at)
SELECT device_id, status, alarm_count, updated_at
FROM staging_device_state
ON DUPLICATE KEY UPDATE SET status = 'UPDATED';
-- MySQLのVALUES(col)関数は未サポートです。
INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET status = VALUES(status);
-- EXCLUDED別名は未サポートです。
INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'))
ON DUPLICATE KEY UPDATE SET status = EXCLUDED.status;
-- conflict target構文は未サポートです。
INSERT INTO ch8_up_device_state VALUES (1, 'ALARM', 1, TO_DATE('2026-07-10 09:00:00', 'YYYY-MM-DD HH24:MI:SS'))
ON CONFLICT (device_id) DO UPDATE SET status = 'ALARM';
```
対象テーブルの制限は次のとおりです。
- このページは、TRANSACTIONのPRIMARY KEY・UNIQUE競合時の動作だけを説明します。
同じSQL形式はLOOKUPとVOLATILEのPRIMARY KEY競合にも対応します。
共通構文の正本は[DMLリファレンス](/ja/dbms/reference/sql/syntax/dml-syntax/#on-duplicate-key-update)です。
- LOGとTAG DATA行ではサポートしていません。TAG METADATAのタグ名競合処理は、
[DMLリファレンス](/ja/dbms/reference/sql/syntax/dml-syntax/#on-duplicate-key-update)を参照してください。
- TRANSACTIONテーブルでも、PRIMARY KEYまたはUNIQUE INDEXがなければ使用できません。
- JSONパスのUNIQUE INDEXは競合判定キーに使用しません。
## 競合とエラー処理
複数のUNIQUE INDEXが同じ既存行を指す場合、その行を一度だけUPDATEします。
一方、異なる既存行と競合すると、更新すべき行を決定できず文が失敗します。
次は、2つの業務キーがそれぞれ異なる行と競合するサンプルです。
```sql
CREATE TRANSACTION TABLE ch8_up_user_contact (
id INTEGER PRIMARY KEY,
email VARCHAR(120),
phone VARCHAR(40),
note VARCHAR(80)
);
CREATE UNIQUE INDEX ch8_up_uidx_user_contact_email ON ch8_up_user_contact(email);
CREATE UNIQUE INDEX ch8_up_uidx_user_contact_phone ON ch8_up_user_contact(phone);
INSERT INTO ch8_up_user_contact VALUES (1, 'a@example.com', '010-0000-0001', 'user-a');
INSERT INTO ch8_up_user_contact VALUES (2, 'b@example.com', '010-0000-0002', 'user-b');
```
次のINSERTだけを意図的に失敗させる任意の実習です。
```sql
-- emailはid=1、phoneはid=2と競合します。
-- 異なる行と競合するため、更新処理を選択せず失敗します。
INSERT INTO ch8_up_user_contact VALUES (3, 'a@example.com', '010-0000-0002', 'ambiguous')
ON DUPLICATE KEY UPDATE SET note = 'updated';
```
`SET`の結果が別のUNIQUE制約や`NOT NULL`制約に違反した場合も、文は失敗して既存行が保持されます。
## 再送と最新状態
カウンター増加のUPSERTは自動的な重複排除ではありません。
同じイベントを再実行すると、既存のカウンターが再び増加します。
COMMIT応答を失った場合は、業務キー・イベント処理記録で先に結果を確認してください。
また、「最新状態」は、入力順序とイベント発生順序が一致する場合にのみ単純な上書きで維持できます。
遅れて到着した過去のイベントが最新値を上書きしないよう、元の時刻の比較と収集ポリシーを別途定めてください。
複数テーブルをまとめて変更する処理では、[障害時のトランザクションのコミット範囲](../transaction/)も確認する必要があります。
## 運用上の推奨事項
- 業務キーが明確なら、PRIMARY KEYまたはUNIQUE INDEXを先に定義します。
- カウンターの累積には、`SET count_col = count_col + 1`形式を使用します。
- ソース行の値をそのまま反映するには、`SET`なしのUPSERTを使用できます。この場合、列リストで省略した列は保持されます。
- 複数のUNIQUE INDEXを持つテーブルでは、異なる行と同時に競合する可能性がある入力を事前に整理します。
- MySQL互換SQLを移植する場合は、`VALUES(col)`、`EXCLUDED`、`ON CONFLICT`をMachbaseのサポート構文に変更します。
- JSONパスのUNIQUE INDEXをUPSERTキーにする設計は避けます。必要なら別の通常列にキー値を保存してUNIQUE INDEXを作成します。
## 結果確認とクリーンアップ
通常の実習を終えたら、代表値と件数を再確認します。
次の想定値は、意図的なエラー以外の正常なSQLをそれぞれ一度実行した場合です。
```sql
SELECT id, email, display_name, login_count
FROM ch8_up_account_profile ORDER BY id;
SELECT device_name, last_state, event_count
FROM ch8_up_latest_device_status;
SELECT external_device_id, device_name, owner_name
FROM ch8_up_customer_device;
SELECT alias_name, tag_name, manually_checked FROM ch8_up_tag_alias_cache;
SELECT alarm_code, hit_count FROM ch8_up_alarm_counter;
SELECT id, status, count_value FROM ch8_up_tx_device_state ORDER BY id;
SELECT id, note FROM ch8_up_user_contact ORDER BY id;
```
| サンプル | 確認する結果 |
|---|---|
| account_profile | id=1を保持、display_name=ops-renamed、login_count=2 |
| latest_device_status | ALARM、event_count=2 |
| customer_device | 外部キーの1行、名前compressor-a-renamed、所有line-2 |
| tag_alias_cache | tag_name=comp_a.temperature、manually_checked=1を保持 |
| alarm_counter | OVER_TEMPのhit_count=2 |
| tx_device_state | ROLLBACK後は既存のid=1、NORMAL、count_value=10だけが存在 |
| user_contact | id=1・2のuser-a・user-bをそのまま保持 |
```sql
DROP TABLE ch8_up_user_contact;
DROP TABLE ch8_up_tx_device_state;
DROP TABLE ch8_up_device_json_state;
DROP TABLE ch8_up_alarm_counter;
DROP TABLE ch8_up_tag_alias_cache;
DROP TABLE ch8_up_customer_device;
DROP TABLE ch8_up_latest_device_status;
DROP TABLE ch8_up_daily_device_summary;
DROP TABLE ch8_up_account_profile;
DROP TABLE ch8_up_asset_cache;
DROP TABLE ch8_up_device_state;
```
DROPはこのページの実習オブジェクトだけを対象にします。
キーが複雑な場合ほど、新しい入力値と競合する既存行を並べて比較してください。
更新しようとした行が明確になれば、エラーの原因も特定しやすくなります。
---
title: "9. LOOKUPテーブルの活用"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/
language: ja
kind: section
---
# 9. LOOKUPテーブルの活用
LOOKUPテーブルは、永続保存した基準情報やマスターデータをサーバー起動時にメモリへロードし、
PRIMARY KEYをキーに高速参照するテーブルです。
メモリ常駐構造、JSON/SEQUENCE、JOIN、一般の述語に基づくDMLを説明します。
## この章の構成
| 節 | 内容 |
|----|------|
| [概要と選択基準](./overview-use-criteria/) | LOOKUPテーブルの用途と適用条件 |
| [テーブル構造とスキーマ](./table-structure-schema/) | 列構成、PK構造、スキーマ設計 |
| [作成、変更、削除](./create-alter-drop/) | DDL: CREATE、ALTER、DROP |
| [データ入力と変更](./data-input-mutation/) | INSERT、Append、再ロード、削除 |
| [クエリと分析](./query-analysis/) | SELECT、JOIN、条件検索 |
| [インデックスとパフォーマンス](./index-performance/) | 赤黒木インデックス、セカンダリインデックス、チューニング |
| [運用とデータライフサイクル](./operations-lifecycle/) | バックアップ・復旧、データの永続性 |
| [制約、エラー、トラブルシューティング](./constraints-errors-troubleshooting/) | 制限、エラー原因、対処 |
| [活用パターンとシナリオ](./patterns-scenarios/) | コードテーブル、マスターデータ、しきい値管理 |
| [PRIMARY KEYポリシー](./primary-key-policy/) | 自然キーと代理キー、PK不変の原則 |
| [SEQUENCE列](./sequence-column/) | 自動増分番号の設定とNEXTVALの使用方法 |
| [JSON列とJSONクエリ](./json-column-query/) | JSON列のサポート範囲、パス条件検索、PRIMARY KEYの制約 |
| [一般述語のUPDATE/DELETE](./predicate-update-delete/) | 非PK・範囲・文字列・日付・JSONパス条件による変更 |
---
title: "9.1 概要と選択基準"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/overview-use-criteria/
language: ja
kind: page
---
# 9.1 概要と選択基準
LOOKUPテーブルは、基準コード、機器マスター、しきい値、設定値など、比較的小規模で頻繁に参照されるデータを保存します。
データは永続保存されますが、SQL検索に使用する全行はメモリに常駐します。
そのため、繰り返し行うキーによる検索と更新に適しています。
## LOOKUPテーブルの特性
LOOKUPテーブルは`CREATE LOOKUP TABLE`文で作成し、`PRIMARY KEY`が必須です。
```sql
CREATE LOOKUP TABLE ch9_overview (
sensor_id VARCHAR(64) PRIMARY KEY,
site VARCHAR(32),
unit VARCHAR(16),
status VARCHAR(16)
);
```
LOOKUPテーブルの主な特性は次のとおりです。
| 項目 | 内容 |
|------|------|
| 主な用途 | コードテーブル、機器マスター、しきい値、参照データ |
| 必須条件 | `PRIMARY KEY`が必要 |
| 保存方式 | 永続保存し、サーバー起動時に全行をメモリへロード |
| 検索パターン | PK検索に最適化。一般条件検索と他のテーブルとのJOINをサポート |
| 変更パターン | INSERT、UPDATE、DELETE |
| 追加機能 | SEQUENCE列、Appendの重複キーポリシー |
## 選択基準
次の条件に該当する場合は、LOOKUPテーブルを使用します。
- データ件数が比較的小さく、全体が頻繁に参照される。
- 全行と必要なセカンダリインデックスをサーバーメモリに保持できる。
- コード、名前、場所、単位、状態などのマスターデータを管理する。
- TAGまたはLOGの元データに説明情報をJOINする必要がある。
- しきい値や設定値など、運用中に変更される参照値を保存する。
- `PRIMARY KEY`で行を明確に識別できる。
TAGまたはLOGデータに場所や単位などの説明を付加するJOIN例は、
[クエリと分析](/ja/dbms/lookup-table-usage/query-analysis/)で説明します。
## 他のテーブルを検討する場合
次の要件には、他のテーブルタイプを検討します。
| 要件 | 推奨テーブル |
|----------|-------------|
| 大量の時系列計測データの保存 | TAG |
| 追加中心の元イベントの保存 | LOG |
| 全行のメモリロードが困難な大規模リレーショナルデータ | TRANSACTION |
| トランザクションとリレーショナルな業務処理が必要なデータ | TRANSACTION |
| サーバーメモリだけで維持する最新状態キャッシュ | VOLATILE |
LOOKUPテーブルは参照データに適していますが、永続保存されることを理由にディスク中心の大容量テーブルとして使用しないでください。
元データはLOGまたはTAGに保存し、LOOKUPにはメモリに常駐させて繰り返し検索するマスターデータを格納します。
リレーショナルデータがメモリ容量を超える場合や、複雑な業務処理が必要な場合はTRANSACTIONテーブルを使用します。
この節の実習テーブルは、次のように削除します。
```sql
DROP TABLE ch9_overview;
```
## 設計手順
LOOKUPテーブルの設計では、次の順序で決定します。
1. 行を識別する`PRIMARY KEY`を決めます。
2. 自然キーか、SEQUENCEまたはAUTO_INCREMENTに基づく代理キーかを決めます。
3. 頻繁に検索・JOINする列にインデックスを追加します。
4. 想定行サイズ・行数と、セカンダリインデックスを含むメモリ使用量を検証します。
5. 運用中に更新する列と不変の列を区別します。
6. 大量変更の前に、対象範囲を確認するクエリを用意します。
スキーマとキーの設計は、[テーブル構造とスキーマ](/ja/dbms/lookup-table-usage/table-structure-schema/)と
[PRIMARY KEYポリシー](/ja/dbms/lookup-table-usage/primary-key-policy/)で説明します。
---
title: "9.2 テーブル構造とスキーマ"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/table-structure-schema/
language: ja
kind: page
---
# 9.2 テーブル構造とスキーマ
LOOKUPテーブルの構造とスキーマ設計を説明します。
## LOOKUPテーブルの設計
LOOKUPテーブルは、コードテーブルとマスターデータを保存するタイプです。
PRIMARY KEYで各行を識別し、PRIMARY KEYまたは一般条件式によるUPDATE/DELETEをサポートし、ディスクに永続保存されます。
### 永続保存とメモリ検索の構造
LOOKUPテーブルは、永続性とメモリ検索性能を提供する2層構造です。
1. 変更された行は、再起動後も保持できるよう永続ストレージに記録されます。
2. サーバー起動時に永続ストレージのLOOKUP行をすべて読み取り、各列の値を含むメモリ上の行として復元します。
3. 各メモリ行は、必須の`PRIMARY KEY`の赤黒木インデックスに登録されます。
4. SQLクエリは、復元されたメモリ行とインデックスを使用します。
概念上、1行は次のようなキーと値の項目として捉えられます。
```
PRIMARY KEY その他の列の値
sensor_id = 'TEMP-01' ───────► { site, unit, status, ... }
key value
```
このためLOOKUPは、SQLテーブルのインターフェース、一般条件検索、JOIN、セカンダリインデックスに対応しながら、
特に`PRIMARY KEY`検索に適しています。
永続ストレージがあっても、検索時に必要な行だけをディスクから読み出す構造ではありません。
全行と作成した赤黒木セカンダリインデックスがメモリを使用するため、スキーマ設計では、
行数だけでなく可変長列、JSON値、セカンダリインデックスのサイズも考慮してください。
- **[活用例](/ja/dbms/lookup-table-usage/patterns-scenarios/#use-cases-lookup)**
- **[PRIMARY KEYの設計](/ja/dbms/lookup-table-usage/primary-key-policy/#design-primary-key)**
- **[列とシーケンスの設計](/ja/dbms/lookup-table-usage/sequence-column/#design-column-lookup-sequence)**
- **[JSON列とクエリ](/ja/dbms/lookup-table-usage/json-column-query/#condition-query-lookup-json)**
- **[参照設計パターン](/ja/dbms/lookup-table-usage/patterns-scenarios/#patterns-reference-design)**
- **[インデックス戦略](/ja/dbms/lookup-table-usage/index-performance/#index-strategy-lookup)**
- **[PRIMARY KEYポリシー](/ja/dbms/lookup-table-usage/primary-key-policy/#policy-lookup-primary-key)**
- **[一般条件式によるUPDATE・DELETE](/ja/dbms/lookup-table-usage/predicate-update-delete/)**
- **[バックアップ・復旧のサポート範囲](/ja/dbms/lookup-table-usage/operations-lifecycle/#recovery-support-scope-backup-lookup)**
- **[制約と注意事項](/ja/dbms/lookup-table-usage/constraints-errors-troubleshooting/#limitations-lookup)**
---
title: "9.3 作成、変更、削除"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/create-alter-drop/
language: ja
kind: page
---
# 9.3 作成、変更、削除
LOOKUPテーブルの作成、変更、削除方法を説明します。
## LOOKUPテーブルの作成と管理
参照テーブルの作成方法は次のとおりです。LOOKUPテーブルには必ず`PRIMARY KEY`を指定します。
## LOOKUPテーブルの作成
```sql
CREATE LOOKUP TABLE ch9_ddl (id INTEGER PRIMARY KEY, name VARCHAR(20));
```
運用で使用するマスターデータには、意味の明確な列名を定義します。
```sql
CREATE LOOKUP TABLE ch9_ddl_equip (
equip_id LONG PRIMARY KEY,
equip_name VARCHAR(128),
location VARCHAR(64),
status VARCHAR(16),
updated_at DATETIME
);
```
`PRIMARY KEY`は行を一意に識別し、UPDATE、DELETE、JOINの基準になります。
複数列の組み合わせが業務キーの場合は、結合した文字列を別のキー列にするか、SEQUENCEによる代理キーを使用します。
```sql
CREATE LOOKUP TABLE ch9_ddl_price (
price_key VARCHAR(64) PRIMARY KEY,
product_id VARCHAR(32),
region VARCHAR(16),
price DOUBLE
);
```
## AUTO_INCREMENT PRIMARY KEY
サーバーが数値PRIMARY KEYを生成する場合は、単一の`LONG`または`INT64`列に`AUTO_INCREMENT`を指定します。
```sql
CREATE LOOKUP TABLE ch9_ddl_registry (
equip_id LONG PRIMARY KEY AUTO_INCREMENT,
equip_name VARCHAR(128),
location VARCHAR(64)
);
INSERT INTO ch9_ddl_registry(equip_name, location)
VALUES ('compressor-01', 'SEOUL-A');
```
PK列を省略するかNULLを指定すると、サーバーが値を生成します。
単一の`INSERT ... VALUES`では、`0..INT64_MAX`範囲のPK値を直接指定することもできます。
指定値が現在の次の自動値以上なら、次の自動値は`指定値 + 1`に進み、小さい値を指定しても戻りません。
データと次の自動値は、正常な再起動後も保持されます。
AUTO_INCREMENTを使用するLOOKUPテーブルでは、`INSERT ... SELECT`と`ON DUPLICATE KEY UPDATE`は使用できません。
SDKでINSERT結果のIDを取得する方法は、[ROWIDとINSERT結果ID](/ja/dbms/reference/sql/rowid/)を参照してください。
## SEQUENCE列の使用
自動増分番号が必要なら、`LONG PROPERTY(SEQUENCE=1)`列を使用します。
入力時は`NEXTVAL()`関数で次の値を取得します。
```sql
CREATE LOOKUP TABLE ch9_ddl_alarm (
seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY,
sensor_id VARCHAR(64),
alarm_type VARCHAR(32),
occurred_at DATETIME,
message VARCHAR(256)
);
INSERT INTO ch9_ddl_alarm
VALUES (NEXTVAL(seq), 'TEMP-01', 'HIGH', NOW, '온도 초과');
```
SEQUENCE列の詳細なポリシーは、[SEQUENCE列](/ja/dbms/lookup-table-usage/sequence-column/)で説明します。
`PROPERTY(SEQUENCE)`と`AUTO_INCREMENT`は別の機能であり、同じ列に併用しません。
## 列の追加と削除
Standard Editionでは、LOOKUPテーブルに固定長の数値ARRAY列を追加・削除できます。
```sql
ALTER TABLE ch9_ddl_equip
ADD COLUMN (limits DECIMAL(12,4)[2] DEFAULT [0.0000, NULL]);
ALTER TABLE ch9_ddl_equip
DROP COLUMN (limits);
```
DEFAULTがなければ、既存行の新しいARRAY列は列全体がNULLになります。
DEFAULTを指定すると、既存行にもその値を適用します。
ARRAY DEFAULTの要素数は、宣言した要素数と正確に一致する必要があります。
ARRAY列はPRIMARY KEYやインデックスキーには使用できません。
サポート型と制約は、[数値ARRAY型](/ja/dbms/reference/sql/types/array/)を参照してください。
## インデックスの追加
頻繁に検索する列やJOIN条件に使用する列には、インデックスを追加します。
```sql
CREATE INDEX ch9_ddl_loc_idx ON ch9_ddl_equip(location);
CREATE INDEX ch9_ddl_status_idx ON ch9_ddl_equip(status);
```
PRIMARY KEY列には標準のインデックスが作成されるため、同じ列に別のインデックスを重複作成しません。
インデックスが多いと入力と更新のコストが増えるため、検索条件が明確な列だけに追加します。
## データ削除とテーブル削除
行を削除するには`DELETE`文を使用します。単一行の削除には、PK条件を使用する方法が最も明確です。
```sql
DELETE FROM ch9_ddl_equip
WHERE equip_id = 1001;
```
一括削除では一般条件式を使用できます。
本番データでは、先に同じ条件で対象件数を確認してください。
```sql
SELECT COUNT(*)
FROM ch9_ddl_equip
WHERE status = 'RETIRED';
DELETE FROM ch9_ddl_equip
WHERE status = 'RETIRED';
```
テーブル自体を削除するには、`DROP TABLE`を使用します。
```sql
DROP TABLE ch9_ddl_alarm;
DROP TABLE ch9_ddl_registry;
DROP TABLE ch9_ddl_price;
DROP TABLE ch9_ddl_equip;
DROP TABLE ch9_ddl;
```
`DROP TABLE`はテーブル定義とデータを両方削除します。
必要に応じて、削除前にバックアップまたはエクスポートを行ってください。
## 注意事項
- LOOKUPテーブルには`PRIMARY KEY`が必須です。
- `PRIMARY KEY`列は1つだけ指定します。
- `PRIMARY KEY`値を変更する場合は、既存行を削除してから新しいキーで挿入します。
- マスターデータが大きくなり、検索・更新パターンが複雑になったら、TRANSACTIONテーブルを検討します。
---
title: "9.4 データ入力と変更"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/data-input-mutation/
language: ja
kind: page
---
# 9.4 データ入力と変更
LOOKUPテーブルの入力、更新、削除を、一連の実行可能な例で説明します。
## サンプルテーブルの準備
次の例は、最後のクリーンアップ文まで順に実行できます。
```sql
CREATE LOOKUP TABLE ch9_mutation (
code VARCHAR(32) PRIMARY KEY,
label VARCHAR(64),
status VARCHAR(16),
updated_at DATETIME
);
INSERT INTO ch9_mutation VALUES ('TEMP', 'Temperature', 'ACTIVE', NOW);
INSERT INTO ch9_mutation VALUES ('PRESS', 'Pressure', 'ACTIVE', NOW);
```
SEQUENCEキーが必要なら、[SEQUENCE](/ja/dbms/lookup-table-usage/sequence-column/)を参照してください。
## UPDATE
単一行の変更はPRIMARY KEY条件で処理します。
```sql
UPDATE ch9_mutation
SET status = 'INACTIVE',
updated_at = NOW
WHERE code = 'TEMP';
```
複数行を変更する場合は、先に同じ`WHERE`句で対象を検索します。
単一行の変更には、対象が明確でインデックスを使用できる`PRIMARY KEY`条件を推奨します。
PRIMARY KEY列自体はUPDATEできません。キーを変更する場合は、既存行を削除して新しいキーで再入力します。
この2文を1つのTRANSACTIONトランザクションにまとめることはできないため、途中の失敗と参照データの変更手順も設計してください。
## 重複キーの処理
SQL INSERTのキー重複時に更新が必要なら、`ON DUPLICATE KEY UPDATE`を使用します。
```sql
INSERT INTO ch9_mutation
VALUES ('TEMP', 'Temperature sensor', 'ACTIVE', NOW)
ON DUPLICATE KEY UPDATE SET label = 'Temperature sensor', status = 'ACTIVE', updated_at = NOW;
```
Appendでデータを挿入するときにPRIMARY KEYが重複すると、`LOOKUP_APPEND_UPDATE_ON_DUPKEY`設定に応じて対象行を更新できます。
この設定はLOOKUPテーブルのAppend処理における重複キーポリシーのため、本番環境では現在の設定値を確認してから使用してください。
```sql
SELECT name, value
FROM v$property
WHERE name = 'LOOKUP_APPEND_UPDATE_ON_DUPKEY';
```
## TABLE_REFRESH
永続保存されたLOOKUPの内容を、実行中のメモリテーブルへ再反映する必要がある場合は、`TABLE_REFRESH`を実行します。
```sql
EXEC TABLE_REFRESH(ch9_mutation);
```
通常のSQL DMLの直後に毎回実行するコマンドではありません。
対象は現在のデータベースのLOOKUPテーブルであり、READ ONLYデータベースでは実行できません。
名前の範囲・権限・エラー仕様は、[EXECプロシージャの正本](/ja/dbms/reference/sql/syntax/execute-procedure-syntax/#table-refresh)、
クラスター運用手順は[運用とライフサイクル](/ja/dbms/lookup-table-usage/operations-lifecycle/)を参照してください。
## LOOKUPデータの削除
単一行の削除にはPRIMARY KEY条件を使用します。
```sql
DELETE FROM ch9_mutation
WHERE code = 'PRESS';
```
一般条件式を使用すると、条件に一致するすべての行を削除します。
全行を削除する場合はWHERE句を省略します。
```sql
DELETE FROM ch9_mutation;
DROP TABLE ch9_mutation;
```
## 変更操作のチェックリスト
- 単一行の変更にはPRIMARY KEY条件を使用します。
- 一般条件式で一括変更する前に、同じ条件で対象範囲を検索します。
- 全行の削除前に、バックアップまたは再入力できる元データを確認します。
- PRIMARY KEY値の変更は、DELETE後のINSERTで処理します。
- Appendの重複キー処理では、`LOOKUP_APPEND_UPDATE_ON_DUPKEY`設定を確認します。
- 永続LOOKUPを実行時メモリに再反映する必要がある場合だけ、`EXEC TABLE_REFRESH(table_name)`を使用します。
---
title: "9.5 クエリと分析"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/query-analysis/
language: ja
kind: page
---
# 9.5 クエリと分析
LOOKUPテーブルのキー検索、一般条件検索、TAGデータとのJOINを実行可能な例で説明します。
## サンプルデータの準備
次のLOOKUPテーブルとTAGテーブルを準備します。
```sql
CREATE LOOKUP TABLE ch9_query_master (
sensor_id VARCHAR(32) PRIMARY KEY,
site VARCHAR(32),
unit VARCHAR(16),
status VARCHAR(16)
);
INSERT INTO ch9_query_master VALUES ('TEMP-01', 'SEOUL', 'C', 'ACTIVE');
INSERT INTO ch9_query_master VALUES ('TEMP-02', 'BUSAN', 'C', 'INACTIVE');
CREATE TAG TABLE ch9_query_data (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
INSERT INTO ch9_query_data VALUES ('TEMP-01', TO_DATE('2026-01-01 00:00:00'), 23.5);
INSERT INTO ch9_query_data VALUES ('TEMP-02', TO_DATE('2026-01-01 00:00:00'), 19.0);
```
## PRIMARY KEYによる検索
単一行の検索には`PRIMARY KEY`条件を使用します。
```sql
SELECT sensor_id, site, unit, status
FROM ch9_query_master
WHERE sensor_id = 'TEMP-01';
```
## 一般条件による検索
LOOKUPテーブルは、一般列の条件でも検索できます。頻繁に使用する条件列にはインデックスを追加します。
```sql
SELECT sensor_id, site, unit
FROM ch9_query_master
WHERE site = 'SEOUL'
AND status = 'ACTIVE';
```
頻繁に使用する一般条件列には、インデックスを追加できます。
インデックスの設計と作成方法は、[インデックス](/ja/dbms/lookup-table-usage/index-performance/)を参照してください。
## TAG・LOGテーブルとのJOIN
LOOKUPテーブルは、TAGまたはLOGテーブルの元データに説明情報を付加する用途でよく使用します。
```sql
SELECT d.name, m.site, m.unit, d.time, d.value
FROM ch9_query_data d
JOIN ch9_query_master m ON d.name = m.sensor_id
WHERE m.status = 'ACTIVE';
```
## 分析パターン
LOOKUPテーブルは元データを保存するより、分析の基準を提供します。次のパターンに適しています。
| パターン | 説明 |
|------|------|
| コード変換 | 状態コード、アラームコード、機器タイプをラベルに変換 |
| 基準値との比較 | センサー値をしきい値テーブルとJOINし、超過を判定 |
| グループ基準の提供 | 場所、部門、ラインなどの集計基準を提供 |
| 最新設定の反映 | 運用中に変更される設定値を検索時点で反映 |
同じ方法で、しきい値のLOOKUPテーブルとTAGの元データをJOINし、基準値を超えたか判定できます。
時間範囲が広いTAGまたはLOGテーブルでは、JOIN前に時間条件で検索範囲を制限します。
```sql
DROP TABLE ch9_query_data CASCADE;
DROP TABLE ch9_query_master;
```
## クエリ性能の基準
- 単一行検索とJOINの基準列には、`PRIMARY KEY`またはインデックス列を使用します。
- 条件に頻繁に使う一般列には、別のインデックスを検討します。
- 大量の元データとJOINする場合は、元テーブルの時間範囲を先に絞ります。
- LOOKUPにはマスターデータ、長期の元データはTAGまたはLOGに保存します。
---
title: "9.6 インデックスとパフォーマンス"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/index-performance/
language: ja
kind: page
---
# 9.6 インデックスとパフォーマンス
LOOKUPテーブルのインデックス構造とパフォーマンスチューニングを説明します。
## LOOKUPのインデックスチューニング
LOOKUPのPRIMARY KEYには赤黒木インデックスが自動作成されます。
全行とインデックスは、SQL検索中にメモリに常駐します。
必要に応じて、非PK列にも赤黒木のセカンダリインデックスを追加できます。
### LOOKUPテーブルのインデックス
#### PKの自動赤黒木インデックス
LOOKUPテーブルを作成すると、PRIMARY KEY列に赤黒木インデックスが自動作成されます。
インデックス項目は、そのキーの全列値を含むメモリ行を指します。
そのため、永続テーブルでもクエリの実行経路はメモリベースであり、小規模なマスターデータをキーで繰り返し検索するパターンに最適化されています。
```sql
CREATE LOOKUP TABLE ch9_index_device (
device_id VARCHAR(64) PRIMARY KEY, -- 赤黒木を自動作成
device_name VARCHAR(128),
location VARCHAR(256),
category VARCHAR(32)
);
INSERT INTO ch9_index_device VALUES ('DEV-01', 'Boiler', 'Seoul', 'temperature');
INSERT INTO ch9_index_device VALUES ('DEV-02', 'Pump', 'Busan', 'pressure');
```
```sql
-- PK検索: 赤黒木インデックスを使用
SELECT device_id, device_name, location FROM ch9_index_device
WHERE device_id = 'DEV-01';
```
1行が返されます。イベントログと結合する場合も、LOOKUP側はPKで検索します。
```sql
CREATE LOG TABLE ch9_index_event (device_id VARCHAR(64), level SHORT);
INSERT INTO ch9_index_event VALUES ('DEV-01', 3);
INSERT INTO ch9_index_event VALUES ('DEV-02', 1);
EXEC TABLE_FLUSH(ch9_index_event);
SELECT e.device_id, e.level, d.location
FROM ch9_index_event e, ch9_index_device d
WHERE e.device_id = d.device_id
ORDER BY e.device_id;
```
2行が返されます。LOG側に時間範囲も指定すると、読み取る元データをさらに減らせます。
#### 非PK列のセカンダリインデックス
非PK列にも赤黒木セカンダリインデックスを作成できます。
セカンダリインデックスがない列でフィルタリングすると、テーブル全体を順次スキャンします。
```sql
-- 頻繁にフィルタリングする非PK列にセカンダリインデックスを作成
CREATE INDEX ch9_index_device_location ON ch9_index_device(location);
SELECT device_id FROM ch9_index_device WHERE location = 'Seoul';
-- インデックスのない列は全体スキャンになる場合があります
SELECT device_id FROM ch9_index_device WHERE category = 'temperature';
```
両方のクエリがDEV-01を返します。結果が同じでもアクセス経路が異なるため、
実際の比較は本番規模のデータで実行計画と併せて確認します。
セカンダリインデックスは検索を高速化しますが、更新コストとメモリ使用量が増えます。
頻繁に使用する条件列だけに作成してください。
#### LOOKUPテーブルの使用指針
PRIMARY KEYと赤黒木セカンダリインデックスの検索コストは、木のサイズに応じて増加します。
インデックスのない条件は、メモリにロードされた全行をスキャンします。
行数だけで使用限界を決めず、全行の実サイズ、可変長値、インデックス数、検索と更新の比率を同じワークロードで測定してください。
サーバー起動時には永続データをすべて読み取り、メモリ行とインデックスを構築するため、起動時間も確認します。
| 使用パターン | 適合性 |
|----------|-------|
| PKで機器情報を検索 | 適している(PK使用) |
| 非PK列でリスト検索 | セカンダリインデックス作成時に適している |
| 少数の基準コードテーブル | 適している |
| 全行がサーバーメモリに収まらない大規模マスターデータ | TRANSACTIONテーブルを検討 |
| リレーショナルトランザクションが必要なマスターデータ | TRANSACTIONテーブルを検討 |
### VOLATILEとの区別
VOLATILEは、再起動時にデータが消失する別のテーブルタイプです。
インデックス設計は[VOLATILEのインデックスとパフォーマンス](/ja/dbms/volatile-table-usage/index-performance/)を参照してください。
### 大容量のマスターデータが必要な場合
LOOKUPテーブルのサイズとセカンダリインデックスの更新コストを考慮し、次のシナリオでは代替方法を検討します。
**シナリオ**: 機器のマスターデータを複数列でフィルタリングし、変更履歴も保持する場合
```sql
-- 代替方法: LOGテーブル + LSM/BITMAPインデックス
CREATE LOG TABLE ch9_index_device_hist (
device_id VARCHAR(64),
device_name VARCHAR(128),
location VARCHAR(256),
category VARCHAR(32),
updated_at DATETIME
);
-- 非PK列にインデックスを作成可能
CREATE INDEX ch9_index_hist_location ON ch9_index_device_hist (location);
CREATE INDEX ch9_index_hist_category ON ch9_index_device_hist (category) INDEX_TYPE BITMAP;
```
ただし、LOGテーブルは追加専用のため、マスターデータの更新パターンに合わせて設計する必要があります。
実習で使用したオブジェクトは、次のように削除します。
```sql
DROP TABLE ch9_index_device_hist;
DROP INDEX ch9_index_device_location;
DROP TABLE ch9_index_event;
DROP TABLE ch9_index_device;
```
### 要点
- PRIMARY KEYインデックスは自動作成されます。
- 繰り返す非PK条件にだけセカンダリインデックスを作成します。
- 行・可変長値・インデックスのメモリ、起動時間、更新負荷を併せて測定します。
---
title: "9.7 運用とデータライフサイクル"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/operations-lifecycle/
language: ja
kind: page
---
# 9.7 運用とデータライフサイクル
LOOKUPテーブルのバックアップ・復旧とデータの永続性を説明します。
LOOKUPテーブルは、ディスクに永続保存される参照データテーブルです。
運用中に値が変わる場合があるため、変更手順、バックアップ、復旧、クエリへの反映時点を併せて管理します。
永続保存と検索時のデータの場所は区別する必要があります。
サーバー起動時に永続保存されたLOOKUPの全行をメモリテーブルへ復元し、`PRIMARY KEY`とセカンダリインデックスを構築します。
稼働中のSQLクエリはこのメモリ構造を使用します。
## データライフサイクル
LOOKUPデータは、作成、入力、更新、参照、バックアップ、復旧の流れで管理します。
```
テーブル作成
└── マスターデータの入力
└── TAG/LOG/TRANSACTIONクエリでJOINまたは参照
└── 運用中のUPDATE/DELETE
└── バックアップ / 復旧 / マウント
```
マスターデータは元のイベントより小規模ですが、クエリ結果の解釈に直接影響します。
そのため、変更前後の値と適用時点を記録する運用手順を設けます。
## マスターデータの変更手順
運用中にLOOKUPデータを変更する場合は、次の順序で進めます。
1. 変更対象行を検索します。
2. 影響範囲を確認します。
3. UPDATEまたはDELETEを実行します。
4. 必要に応じて`EXEC TABLE_REFRESH(table_name)`を実行します。
5. 代表的なクエリで反映を確認します。
`TABLE_REFRESH`は、通常のSQL DMLの直後に毎回実行するコマンドではありません。
永続LOOKUPの内容を実行時のメモリテーブルに再反映する必要があるときに使用します。
名前の範囲・権限・エラー仕様は、[EXECプロシージャの正本](/ja/dbms/reference/sql/syntax/execute-procedure-syntax/#table-refresh)を参照してください。
次は、この手順をそのまま実行する実習です。
```sql
CREATE LOOKUP TABLE ch9_ops_sensor (
sensor_id VARCHAR(32) PRIMARY KEY,
site VARCHAR(16),
status VARCHAR(16),
updated_at DATETIME
);
INSERT INTO ch9_ops_sensor VALUES ('TEMP-01', 'SEOUL', 'READY', NOW);
INSERT INTO ch9_ops_sensor VALUES ('TEMP-02', 'SEOUL', 'READY', NOW);
INSERT INTO ch9_ops_sensor VALUES ('TEMP-03', 'BUSAN', 'READY', NOW);
-- 変更対象を検索します。
SELECT sensor_id, site, status FROM ch9_ops_sensor WHERE sensor_id = 'TEMP-01';
-- 変更します。
UPDATE ch9_ops_sensor
SET status = 'INACTIVE', updated_at = NOW
WHERE sensor_id = 'TEMP-01';
-- 必要ならメモリテーブルに再反映します。
EXEC TABLE_REFRESH(ch9_ops_sensor);
-- 代表的なクエリで確認します。
SELECT sensor_id, status FROM ch9_ops_sensor ORDER BY sensor_id;
```
TEMP-01だけが`INACTIVE`になり、残りの2行は`READY`のままです。
一括変更では、必ず先に対象件数を確認します。
```sql
SELECT COUNT(*) FROM ch9_ops_sensor
WHERE site = 'SEOUL' AND status = 'READY';
```
TEMP-01は変更済みのためCOUNTは1です。変更前に数えなければ、対象が変わります。
```sql
DROP TABLE ch9_ops_sensor;
```
## バックアップ・復旧のサポート範囲
LOOKUPはディスクに永続保存され、データベースのバックアップに含まれます。
リストア後は行をメモリテーブルとインデックスに再構築します。
共通のBACKUP・RESTORE・MOUNTコマンドとEditionの範囲は、
[バックアップ・リストア・マウント](/ja/dbms/operations-configuration-recovery/backup-restore-mount/)を正本とします。
復旧後に代表的なキーとJOIN結果を検証してください。
## 運用点検項目
- マスターデータの変更履歴を、別のログや運用手順で残します。
- 大量のUPDATE/DELETE前に対象件数を確認します。
- 頻繁にJOINする列にはインデックスを検討します。
- 実際のデータ規模で、サーバー起動時間とLOOKUPの行・インデックスのメモリ使用量を点検します。
- Appendの重複キー処理を使用する場合は、`LOOKUP_APPEND_UPDATE_ON_DUPKEY`設定を確認します。
- バックアップからの復旧後は、代表的なJOINクエリで参照結果を確認します。
---
title: "9.8 制約、エラー、トラブルシューティング"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/constraints-errors-troubleshooting/
language: ja
kind: page
---
# 9.8 制約、エラー、トラブルシューティング
LOOKUPテーブルの制約、発生し得るエラー、解決方法を説明します。
## 制約の概要
| 項目 | 制約 | 代表的なエラー |
|---|---|---|
| PRIMARY KEY | 必須。1つだけ指定 | `ERR-02322`, `ERR-02171` |
| PRIMARY KEY列 | `SET`の対象に指定不可 | `ERR-02176` |
| 列の型 | `TEXT`・`CLOB`・`BLOB`・`BINARY`は使用不可 | `ERR-02173` |
| JSON列 | 一般列として使用可能。PRIMARY KEYには使用不可 | — |
| メモリ | VOLATILEと1つの上限を共有 | `ERR-01344` |
| UPDATE | `WHERE`必須。省略時は実行されない | — |
## PRIMARY KEYのエラー
LOOKUPはPRIMARY KEYなしでは作成できず、2つ以上指定することもできません。
次の2文は、それぞれ失敗します。
```sql
-- 失敗: PRIMARY KEYがありません。(ERR-02322)
CREATE LOOKUP TABLE ch9_err_nopk (code VARCHAR(16), label VARCHAR(64));
-- 失敗: PRIMARY KEYが2つあります。(ERR-02171)
CREATE LOOKUP TABLE ch9_err_twopk (
code VARCHAR(16) PRIMARY KEY,
name VARCHAR(32) PRIMARY KEY
);
```
どちらの文もテーブルを作成しないため、削除するオブジェクトはありません。
複合キーが必要なら、区切り文字で組み合わせた単一のキー列を用意し、
[PRIMARY KEYポリシー](../primary-key-policy/)の設計基準に従ってください。
PRIMARY KEY列の値は変更できません。
```sql
CREATE LOOKUP TABLE ch9_err_pk (code VARCHAR(16) PRIMARY KEY, label VARCHAR(64));
INSERT INTO ch9_err_pk VALUES ('KR', '대한민국');
-- 失敗: PRIMARY KEY列はSETの対象外です。(ERR-02176)
UPDATE ch9_err_pk SET code = 'KO' WHERE code = 'KR';
```
キーを変更する場合は、既存行を削除し、新しいキーで再入力します。
## 未サポートの列型
`TEXT`、`CLOB`、`BLOB`、`BINARY`はLOOKUP列に使用できません。
長い文字列は`VARCHAR`で宣言し、原文の保持が必要ならLOGテーブルに分離します。
```sql
-- 失敗: 未サポートの列型です。(ERR-02173)
ALTER TABLE ch9_err_pk ADD COLUMN (memo TEXT);
```
JSONは一般列として使用できます。
使用範囲は[JSON列とクエリ](../json-column-query/)を参照してください。
```sql
DROP TABLE ch9_err_pk;
```
## メモリ上限
LOOKUPはディスクに永続保存されますが、クエリの実行経路はメモリです。
サーバー起動時に全行とインデックスをメモリへロードするため、使用量が上限を超えると`ERR-01344`が発生します。
この上限は**VOLATILEテーブルと共有します。**
設定名は`VOLATILE_`で始まりますが、LOOKUPも同じ上限に含まれるため、両タイプを併用する環境では合計で判断する必要があります。
```sql
SELECT NAME, VALUE FROM V$PROPERTY
WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE';
SELECT * FROM V$STORAGE_DC_VOLATILE_TABLE;
```
上限に近づいたら、保持範囲の縮小や未使用のセカンダリインデックスの削除を行います。
大規模なマスターデータでは、[インデックスとパフォーマンス](../index-performance/)の基準に従って他のテーブルタイプを検討してください。
## 複数行の変更範囲
一般述語のUPDATE/DELETEは、複数行に適用される場合があります。
実行前に同じ述語で対象数を確認し、[一般述語のUPDATE/DELETE](../predicate-update-delete/)の仕様に従ってください。
## LOOKUPのJSON PRIMARY KEYエラー
JSON列は一般列として使用できますが、PRIMARY KEYには宣言できません。
識別子を別のスカラー列に格納し、[JSON列とクエリ](../json-column-query/)の型・パス規則に従ってください。
## 制約と注意事項
- PRIMARY KEYのポリシーは、[PRIMARY KEYポリシー](../primary-key-policy/)を参照してください。
- メモリ規模とインデックスのコストは、[インデックスとパフォーマンス](../index-performance/)で測定します。
- 時系列の元データにはTAG、再起動後に消えてもよいキャッシュにはVOLATILEを選択します。
- Appendの使用条件は、[SDK Append対応表](/ja/dbms/development-tools-integration/sdk-support-scope/#append-table-type-matrix)に従います。
---
title: "9.9 活用パターンとシナリオ"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/patterns-scenarios/
language: ja
kind: page
---
# 9.9 活用パターンとシナリオ
LOOKUPテーブルの活用パターンとシナリオを説明します。
## 活用例
LOOKUPテーブルは、次のようなデータの保存に適しています。
## 適したデータの種類
| 種類 | 例 |
|------|------|
| コードテーブル | 国コード、言語コード、状態コード |
| マスターデータ | 設備一覧、製品分類、部門情報 |
| リアルタイム更新の参照データ | 為替レートテーブル、しきい値設定 |
| タグメタデータの代替 | センサー情報(小規模) |
## コードテーブル
```sql
CREATE LOOKUP TABLE ch9_pattern_country (
code VARCHAR(4) PRIMARY KEY,
name VARCHAR(64),
region VARCHAR(32)
);
INSERT INTO ch9_pattern_country VALUES ('KR', '대한민국', 'Asia');
INSERT INTO ch9_pattern_country VALUES ('US', '미국', 'America');
UPDATE ch9_pattern_country SET name = 'United States' WHERE code = 'US';
SELECT code, name FROM ch9_pattern_country ORDER BY code;
```
2行が返され、US行のnameだけが`United States`に変わっています。
状態コードやアラームコードも同じ方法で管理し、元のイベントとJOINして使用します。
```sql
CREATE LOOKUP TABLE ch9_pattern_status (
code VARCHAR(16) PRIMARY KEY,
label VARCHAR(64),
color VARCHAR(16)
);
INSERT INTO ch9_pattern_status VALUES ('RUN', '가동', 'green');
INSERT INTO ch9_pattern_status VALUES ('STOP', '정지', 'red');
CREATE LOG TABLE ch9_pattern_event (
event_time DATETIME,
device_id VARCHAR(64),
status VARCHAR(16)
);
INSERT INTO ch9_pattern_event
VALUES (TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 'DEV-01', 'RUN');
INSERT INTO ch9_pattern_event
VALUES (TO_DATE('2026-01-01 10:05:00', 'YYYY-MM-DD HH24:MI:SS'), 'DEV-01', 'STOP');
EXEC TABLE_FLUSH(ch9_pattern_event);
SELECT e.event_time, e.device_id, c.label
FROM ch9_pattern_event e
JOIN ch9_pattern_status c ON e.status = c.code
ORDER BY e.event_time;
```
2行がコードの代わりに`가동`(稼働)・`정지`(停止)のラベルで返されます。
コードにない状態がイベントに含まれるとINNER JOINでその行が除外されるため、コードテーブルの欠落も点検します。
## 設備マスター
```sql
CREATE LOOKUP TABLE ch9_pattern_equip (
equip_id VARCHAR(32) PRIMARY KEY,
equip_name VARCHAR(128),
location VARCHAR(64),
dept VARCHAR(64),
install_dt DATETIME
);
INSERT INTO ch9_pattern_equip
VALUES ('TEMP-01', 'Boiler', 'Seoul', 'Production',
TO_DATE('2025-01-01', 'YYYY-MM-DD'));
INSERT INTO ch9_pattern_equip
VALUES ('TEMP-02', 'Chiller', 'Busan', 'Facility',
TO_DATE('2025-01-01', 'YYYY-MM-DD'));
```
TAGテーブルのセンサーデータとJOINすると、場所や部門などのマスターデータも検索できます。
```sql
CREATE TAG TABLE ch9_pattern_sensor (
name VARCHAR(32) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED
);
INSERT INTO ch9_pattern_sensor
VALUES ('TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 90.0);
INSERT INTO ch9_pattern_sensor
VALUES ('TEMP-02', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 20.0);
EXEC TABLE_FLUSH(ch9_pattern_sensor);
SELECT d.name, m.location, m.dept, d.value
FROM ch9_pattern_sensor d
JOIN ch9_pattern_equip m ON d.name = m.equip_id
WHERE m.dept = 'Production'
ORDER BY d.name;
```
TEMP-01の1行だけが返されます。部門条件はLOOKUP側の列に適用されるため、
条件を変更すると、読み取るTAGの元データが同じでも結果集合が変わります。
## しきい値設定
```sql
CREATE LOOKUP TABLE ch9_pattern_threshold (
sensor_name VARCHAR(64) PRIMARY KEY,
low_limit DOUBLE,
high_limit DOUBLE,
alert_level SHORT
);
INSERT INTO ch9_pattern_threshold VALUES ('TEMP-01', 0.0, 100.0, 1);
INSERT INTO ch9_pattern_threshold VALUES ('TEMP-02', 0.0, 100.0, 1);
-- リアルタイムのしきい値変更
UPDATE ch9_pattern_threshold SET high_limit = 85.0 WHERE sensor_name = 'TEMP-01';
```
しきい値テーブルは、TAGデータと結合してアラーム条件を判定するために使用します。
```sql
SELECT s.name, s.value, t.high_limit
FROM ch9_pattern_sensor s
JOIN ch9_pattern_threshold t ON s.name = t.sensor_name
WHERE s.value > t.high_limit
ORDER BY s.name;
```
TEMP-01だけが超過と判定されます。値90は変更前の上限100では正常でした。
同じ元データでもしきい値の変更時点によって判定が変わることを、併せて記録してください。
## SEQUENCEによる履歴番号
小規模な管理履歴や運用イベントに連番が必要なら、SEQUENCE列を使用できます。
```sql
CREATE LOOKUP TABLE ch9_pattern_note (
seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY,
target_id VARCHAR(64),
note VARCHAR(512),
created_at DATETIME
);
INSERT INTO ch9_pattern_note
VALUES (NEXTVAL(seq), 'TEMP-01', 'threshold changed', NOW);
INSERT INTO ch9_pattern_note
VALUES (NEXTVAL(seq), 'TEMP-02', 'inspection done', NOW);
SELECT seq, target_id FROM ch9_pattern_note ORDER BY seq;
```
seqは1と2です。大量の元履歴データは、LOOKUPよりLOGテーブルに保存してください。
このページの実習オブジェクトは、次のように削除します。
```sql
DROP TABLE ch9_pattern_note;
DROP TABLE ch9_pattern_threshold;
DROP TABLE ch9_pattern_sensor;
DROP TABLE ch9_pattern_equip;
DROP TABLE ch9_pattern_event;
DROP TABLE ch9_pattern_status;
DROP TABLE ch9_pattern_country;
```
## 適さない場合
- 明示的トランザクションと一般的なリレーショナルDMLが必要なデータ → TRANSACTIONテーブルを推奨
- UPDATEが不要な追加専用の履歴 → LOGテーブルを推奨
- センサー計測値 → TAGテーブルを推奨
- 再起動後に消えてもよい最新状態キャッシュ → VOLATILEテーブルを推奨
---
title: "9.10 PRIMARY KEYポリシー"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/primary-key-policy/
language: ja
kind: page
---
# 9.10 PRIMARY KEYポリシー
LOOKUPテーブルのPRIMARY KEY設計原則とポリシーを説明します。
SDKがSELECT結果からPKを判定する方法は、
[PRIMARY KEYメタデータのサポート範囲](/ja/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-primary-key-metadata)を参照してください。
## PRIMARY KEYの設計
LOOKUPテーブルには`PRIMARY KEY`が必須です。
PRIMARY KEYは行を一意に識別し、重複入力を制御します。
UPDATEとDELETEの`WHERE`句には一般条件式を使用できますが、PRIMARY KEY列自体はUPDATEできません。
### 基本構文
```text
CREATE LOOKUP TABLE table_name (
pk_col type PRIMARY KEY,
col2 type,
...
);
```
### 単一列のPRIMARY KEY
```sql
CREATE LOOKUP TABLE ch9_pk_country_code (
code VARCHAR(4) PRIMARY KEY,
name VARCHAR(64),
region VARCHAR(32)
);
```
### 複合キーが必要な場合
```sql
CREATE LOOKUP TABLE ch9_pk_price (
price_key VARCHAR(64) PRIMARY KEY,
product_id VARCHAR(32),
region VARCHAR(16),
price DOUBLE
);
-- 挿入
INSERT INTO ch9_pk_price VALUES ('PROD-01:KR', 'PROD-01', 'KR', 99.0);
INSERT INTO ch9_pk_price VALUES ('PROD-01:US', 'PROD-01', 'US', 79.0);
-- 組み合わせキーによるUPDATE
UPDATE ch9_pk_price SET price = 89.0
WHERE price_key = 'PROD-01:KR';
```
LOOKUPテーブルにはPRIMARY KEY列を1つだけ指定できます。
複数列の組み合わせが業務キーの場合は、組み合わせた文字列または代理キーを別のPRIMARY KEY列に格納します。
### PRIMARY KEYの型の選択
| 型 | 利点 | 欠点 |
|------|------|------|
| `VARCHAR(n)` | 可読性が高く、意味のあるキー | 文字列の比較コスト |
| `INTEGER` / `LONG` | 比較が高速で保存効率がよい | 意味を持たず、別のマッピングが必要 |
### 注意事項
- PRIMARY KEY値は重複できません。
- PRIMARY KEY値は変更できません(変更時はDELETE + INSERT)。
- PRIMARY KEY列にはインデックスが自動作成されます。
- PRIMARY KEY列は1つだけ指定します。
## PRIMARY KEYポリシー
PRIMARY KEY設計で考慮するポリシーと推奨方法を説明します。
### 自然キーと代理キー
#### 自然キー(Natural Key)
業務上の意味を持つ値を、そのままPRIMARY KEYに使用します。
```sql
-- 国コード: 標準化された自然キー
CREATE LOOKUP TABLE ch9_pk_country (
iso_code VARCHAR(4) PRIMARY KEY, -- ISO 3166-1 alpha-2
name VARCHAR(64)
);
```
**利点**: 意味を理解しやすく、別の検索が不要
**欠点**: キー変更時に参照整合性の問題が発生
#### 代理キー(Surrogate Key)
SEQUENCE列やUUIDなど、業務上の意味を持たない値をPRIMARY KEYに使用します。
```sql
-- 設備マスター: 代理キー
CREATE LOOKUP TABLE ch9_pk_equip (
equip_id LONG PROPERTY(SEQUENCE=1) PRIMARY KEY,
code VARCHAR(32), -- 業務キー
name VARCHAR(128)
);
CREATE INDEX ch9_pk_equip_idx ON ch9_pk_equip(code);
```
**利点**: 不変で、結合が効率的
**欠点**: コードとIDの変換が必要
### PRIMARY KEY不変の原則
PRIMARY KEY値はUPDATEできません。変更が必要ならDELETE + INSERTを使用します。
```sql
-- 誤ったパターン(PK変更はDELETE + INSERTで実行)
-- UPDATEではPKを変更できません
-- 正しいパターン
DELETE FROM ch9_pk_country WHERE iso_code = 'OLD';
INSERT INTO ch9_pk_country VALUES ('NEW', '새 국가명');
```
LOOKUPテーブルのDMLは個々の文単位で実行します。
`BEGIN`/`COMMIT`でまとめるTRANSACTIONトランザクションに、LOOKUPのDMLを含めることはできません。
したがって、2文の間の検索や挿入失敗に備える必要があります。
既存値を保持し、参照キーの切り替え順序を決めてから変更してください。
変更全体のアトミック性が必要なら、TRANSACTIONテーブルを検討します。
このページの実習テーブルは、次のように削除します。
```sql
DROP INDEX ch9_pk_equip_idx;
DROP TABLE ch9_pk_equip;
DROP TABLE ch9_pk_country;
DROP TABLE ch9_pk_price;
DROP TABLE ch9_pk_country_code;
```
---
title: "9.11 SEQUENCE列"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/sequence-column/
language: ja
kind: page
---
# 9.11 SEQUENCE列
LOOKUPテーブルのSEQUENCE列の設定と活用を説明します。
## LOOKUPのSEQUENCE列の定義
SEQUENCE列は、`NEXTVAL`で入力番号を生成するために使用します。
LOOKUPテーブルは[PRIMARY KEYが必須](../primary-key-policy/)のため、
SEQUENCE列自体をPRIMARY KEYにするか、他の列をPRIMARY KEYにするかも決めます。
この番号を、イベント発生時刻の順序と同じものとして解釈しないでください。
## SEQUENCE列が必要な理由
同時刻に発生したアラームや管理履歴を、別々の行として識別する場合に使用できます。
LOOKUPは全行をメモリに保持するため、この例は小規模な管理履歴を対象とします。
長期間蓄積する大量イベントには、LOGテーブルを検討してください。
## SEQUENCE列の宣言
SEQUENCEは`LONG`または`INT64`型の列に指定できます。
PROPERTY句の`SEQUENCE`パラメーターで開始値を設定します。この属性はLOOKUPテーブルだけで使用できます。
```sql
CREATE LOOKUP TABLE ch9_sequence (
seq LONG PROPERTY(SEQUENCE=1) PRIMARY KEY,
sensor_id VARCHAR(40),
alarm_type VARCHAR(20),
occurred_at DATETIME,
message VARCHAR(200)
);
```
- `SEQUENCE=1`: seq列が1から自動増分します。
- 開始値は1以上4,294,967,295未満の整数だけを指定できます。
- 上の例のようにSEQUENCE列をPRIMARY KEYにすると、番号の一意性も保証されます。
## SEQUENCE値の挿入: NEXTVAL()
サーバーはSEQUENCE列ごとに次に使用する番号をカウンターで保持し、`NEXTVAL()`はその値を取得して挿入します。
毎回テーブルの最大値を再計算することはありません。
```sql
-- NEXTVAL()で自動増分値を入力
INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message)
VALUES (NEXTVAL(seq), 'TEMP-01', 'HIGH', NOW, '온도 초과');
INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message)
VALUES (NEXTVAL(seq), 'PRESS-02', 'LOW', NOW, '압력 저하');
-- 検索
SELECT * FROM ch9_sequence ORDER BY seq;
-- seq=1、seq=2の順にソート
```
## 一般列と同様の直接値指定
SEQUENCE列に値を直接入力することもできます。
入力値が現在のカウンターより大きければ、カウンターは`入力値 + 1`に進みます。
現在のカウンターより小さい値を入力しても、カウンターは減少しません。
```sql
-- 値を直接指定(nextvalは不要)
INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message)
VALUES (100, 'FLOW-03', 'NORMAL', NOW, '정상 복구');
-- 以後のNEXTVAL()呼び出しは101になります
INSERT INTO ch9_sequence (seq, sensor_id, alarm_type, occurred_at, message)
VALUES (NEXTVAL(seq), 'TEMP-01', 'NORMAL', NOW, '온도 정상');
-- seq = 101
```
## 活用パターン
```sql
-- 最新アラームN件を検索
SELECT * FROM ch9_sequence ORDER BY seq DESC LIMIT 10;
-- 特定のseq以降のアラームを検索
SELECT * FROM ch9_sequence WHERE seq > 500 ORDER BY seq;
-- アラーム確認処理(PKによるUPDATE)
UPDATE ch9_sequence SET alarm_type = 'ACKNOWLEDGED'
WHERE seq = 101;
```
実習テーブルは、次のように削除します。
```sql
DROP TABLE ch9_sequence;
```
## 注意事項
- SEQUENCE列は`LONG`、`INT64`型をサポートします。
- 開始値は正数(`SEQUENCE=1`以上)のみ許可され、4,294,967,295未満である必要があります。
- カウンターはサーバーに保存され、増加方向だけに進みます。最大のseq行をDELETEしても番号は再使用されないため、欠番が生じる場合があります。
- SEQUENCE列をPRIMARY KEYにしない場合、`NEXTVAL()`を使わずに重複値を直接入力できます。
番号の一意性が必要なら、この列をPRIMARY KEYに指定してください。
---
title: "9.12 JSON列とJSONクエリ"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/json-column-query/
language: ja
kind: page
---
# 9.12 JSON列とJSONクエリ
LOOKUPテーブルのJSON列のサポート範囲と、JSON条件によるクエリを説明します。
## LOOKUPのJSON条件検索
LOOKUPテーブルは、`JSON`列を一般列としてサポートします。
JSON列は、可変的な属性値を参照データと一緒に保存する場合に使用できます。
```sql
CREATE LOOKUP TABLE ch9_json (
sensor_id VARCHAR(80) PRIMARY KEY,
location VARCHAR(200),
config JSON
);
INSERT INTO ch9_json VALUES (
'TEMP-01',
'factory1',
'{"unit":"celsius","level":3,"threshold":{"high":90.0}}'
);
SELECT sensor_id, config
FROM ch9_json
WHERE config->'$.unit' = 'celsius';
```
## 型別のJSON条件
数値を数値として比較する場合は、型別のJSON抽出関数を使用します。
```sql
SELECT sensor_id
FROM ch9_json
WHERE JSON_EXTRACT_INTEGER(config, '$.level') >= 3
AND JSON_EXTRACT_DOUBLE(config, '$.threshold.high') > 80.0;
```
JSON構造自体も確認できます。
```sql
SELECT sensor_id
FROM ch9_json
WHERE JSON_IS_VALID(config) = 1
AND JSON_TYPEOF(config, '$.threshold') = 'Object';
```
## PRIMARY KEYの制約
LOOKUPテーブルはJSON列を保存できますが、JSON列を`PRIMARY KEY`には使用できません。
行識別子には、`INTEGER`、`LONG`、`VARCHAR`などの安定した一般型を使用します。
```sql
-- 失敗: JSON列はPRIMARY KEYに使用できません。
CREATE LOOKUP TABLE ch9_json_bad (
config JSON PRIMARY KEY,
note VARCHAR(80)
);
```
```sql
-- 推奨: 別の識別子をPRIMARY KEYに使用します。
CREATE LOOKUP TABLE ch9_json_ok (
sensor_id VARCHAR(80) PRIMARY KEY,
config JSON,
note VARCHAR(80)
);
```
## 設計基準
| 状況 | 推奨方法 |
|------|----------|
| 結合・検索で頻繁に使用する値 | 別の列 |
| 機器ごとに異なる可変属性 | JSON列 |
| 数値条件検索 | 一般の数値列に分離 |
| PRIMARY KEY | 安定した識別子列を使用 |
| 高頻度のパス検索 | 別の列に抽出 |
JSONパスごとの専用インデックスはサポートしていません。
高頻度の検索条件は別の列に分離し、その列にインデックスを適用する設計を先に検討してください。
```sql
CREATE LOOKUP TABLE ch9_json_fast (
sensor_id VARCHAR(80) PRIMARY KEY,
unit VARCHAR(16),
level INTEGER,
config JSON
);
CREATE INDEX ch9_json_unit_idx ON ch9_json_fast(unit);
```
## UPDATE・DELETEの条件
```sql
UPDATE ch9_json
SET location = 'factory2'
WHERE config->'$.unit' = 'celsius';
DELETE FROM ch9_json
WHERE JSON_EXTRACT_INTEGER(config, '$.level') < 2;
```
対象範囲が広くなる場合があるため、UPDATE/DELETE前に同じ条件で件数を確認します。
このページの実習オブジェクトは、次のように削除します。
`ch9_json_bad`は作成に失敗する例なので、削除対象ではありません。
```sql
DROP TABLE ch9_json_fast;
DROP TABLE ch9_json_ok;
DROP TABLE ch9_json;
```
## 注意事項
- LOOKUPテーブルは、JSON列を一般列としてサポートします。
- JSON列はPRIMARY KEYには使用できません。
- JSONパスごとの専用インデックスはサポートしていません。
- 頻繁に検索する値は、LOOKUPの一般列に分離します。
- JSONパスインデックスが必要なら、TRANSACTIONまたはTAGテーブルを検討します。
---
title: "9.13 一般述語のUPDATE/DELETE"
url: https://docs.machbase.com/ja/dbms/lookup-table-usage/predicate-update-delete/
language: ja
kind: page
---
# 9.13 一般述語のUPDATE/DELETE
LOOKUPテーブルは、主キーだけでなく一般条件式で複数行を更新・削除できます。
変更前に同じ条件で対象行数を確認してください。
このページの実習は、次の1つのテーブルで進め、最後に削除します。
```sql
CREATE LOOKUP TABLE ch9_predicate (
equip_id VARCHAR(32) PRIMARY KEY,
site VARCHAR(16),
status VARCHAR(16),
score INTEGER
);
INSERT INTO ch9_predicate VALUES ('EQ-01', 'SEOUL', 'READY', 10);
INSERT INTO ch9_predicate VALUES ('EQ-02', 'SEOUL', 'READY', 20);
INSERT INTO ch9_predicate VALUES ('EQ-03', 'SEOUL', 'RETIRED', 30);
INSERT INTO ch9_predicate VALUES ('EQ-04', 'BUSAN', 'READY', 40);
```
## UPDATE
条件に一致するすべての行を更新します。
`SET`式は現在の行値を参照できますが、主キー列自体は変更できません。
LOOKUP UPDATEには`WHERE`条件が必要です。
全行を更新する場合でも、サポートされる条件式を明示してください。
`WHERE`なしで全件削除できるDELETEとは区別してください。
```sql
-- 変更前に影響範囲を数えます。
SELECT COUNT(*) FROM ch9_predicate
WHERE site = 'SEOUL' AND status = 'READY';
UPDATE ch9_predicate
SET status = 'ACTIVE', score = score + 10
WHERE site = 'SEOUL' AND status = 'READY';
SELECT equip_id, site, status, score FROM ch9_predicate ORDER BY equip_id;
```
COUNTは2で、EQ-01とEQ-02だけが`ACTIVE`に変わり、scoreは20・30になります。
同じSEOULでもstatusが異なるEQ-03、同じREADYでもsiteが異なるEQ-04は変わりません。
## DELETE
条件に一致するすべての行を削除します。
`WHERE`を省略すると、テーブルの全行が削除されます。
```sql
SELECT COUNT(*) FROM ch9_predicate WHERE status = 'RETIRED';
DELETE FROM ch9_predicate WHERE status = 'RETIRED';
SELECT equip_id, status FROM ch9_predicate ORDER BY equip_id;
```
COUNTは1で、EQ-03が削除されて3行が残ります。
## 条件の設計指針
1. 単一行の変更には主キー条件を使用します。
2. 一括変更前に、同じ条件の`SELECT COUNT(*)`で影響範囲を確認します。
3. 頻繁にフィルタリングするJSON値は、一般列に分離してインデックスを適用する方法を検討します。
4. 主キーを変更する場合は、既存行を削除して新しいキーで挿入します。
サポートされる演算子とJSON条件の正確な範囲は、SQLリファレンスで確認してください。
- [LOOKUPの述語UPDATE](/ja/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-update-syntax/)
- [LOOKUPの述語DELETE](/ja/dbms/reference/sql/syntax/dml-syntax/lookup-predicate-delete-syntax/)
## 権限とパフォーマンス
UPDATEとDELETEには、それぞれ対象テーブルの`UPDATE`、`DELETE`権限が必要です。
アプリケーションが変更前後の値を直接検索する場合だけ、`SELECT`も付与します。
権限SQLの正本は[権限管理](/ja/dbms/security-access-control/privileges/)です。
主キーの等価条件は単一行を直接検索し、一般条件式は条件を評価して変更対象を収集します。
繰り返す単一行の変更には、プリペアドステートメントとバインドを使用します。
大量変更は、同じ条件の行数と実行時間を検証環境で測定してください。
```sql
DROP TABLE ch9_predicate;
```
---
title: "10. VOLATILEテーブルの活用"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/
language: ja
kind: section
---
# 10. VOLATILEテーブルの活用
VOLATILEテーブルは、サーバープロセス内で共有されるメモリテーブルです。
再起動時のデータ消失、UPSERT、再作成可能なキャッシュパターンを説明します。
## この章の構成
| 節 | 内容 |
|----|------|
| [概要と選択基準](./overview-use-criteria/) | VOLATILEテーブルの特性と適用判断基準 |
| [テーブル構造とスキーマ](./table-structure-schema/) | PRIMARY KEY設計、列の型、スキーマ構成 |
| [作成、変更、削除](./create-alter-drop/) | CREATE VOLATILE TABLE、DROP、永続性の違い |
| [データ入力と変更](./data-input-mutation/) | INSERT、ON DUPLICATE KEY UPDATE、DELETE |
| [クエリと分析](./query-analysis/) | SELECT、条件検索、LIKE |
| [インデックスとパフォーマンス](./index-performance/) | 赤黒木インデックス、PKインデックス |
| [運用とデータライフサイクル](./operations-lifecycle/) | 運用手順とデータ管理 |
| [制約、エラー、トラブルシューティング](./constraints-errors-troubleshooting/) | 機能制約とエラー対応 |
---
title: "10.1 概要と選択基準"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/overview-use-criteria/
language: ja
kind: page
---
# 10.1 概要と選択基準
VOLATILEテーブルは、データをメモリに保存する一時テーブルです。
サーバーを再起動するとデータが消失するため、再作成可能な最新状態、一時集計、セッション間の共有キャッシュに使用します。
## VOLATILEテーブルの特性
VOLATILEテーブルは`CREATE VOLATILE TABLE`文で作成します。
```sql
CREATE VOLATILE TABLE ch10_overview (
sensor_id VARCHAR(64) PRIMARY KEY,
value DOUBLE,
updated_at DATETIME
);
```
VOLATILEテーブルの主な特性は次のとおりです。
| 項目 | 内容 |
|------|------|
| 主な用途 | 最新状態のキャッシュ、一時集計、中間結果 |
| 保存場所 | メモリ |
| 再起動後のデータ | 消失 |
| 共有範囲 | サーバー全体で共有 |
| キー | PRIMARY KEYは任意 |
| 主な機能 | UPDATE、DELETE、`ON DUPLICATE KEY UPDATE`、赤黒木インデックス |
| バックアップ | 未サポート |
## 選択基準
次の条件に該当する場合は、VOLATILEテーブルを使用します。
- サーバー再起動後にデータが失われても問題がない。
- 元データからいつでも再計算または再構築できる。
- 最新状態、直近の集計、一時処理結果を高速に検索する必要がある。
- 複数のセッションで同じ一時状態を共有する必要がある。
- ディスクの永続性より、メモリによる応答時間を重視する。
最新のセンサー状態を維持する例は次のとおりです。
```sql
INSERT INTO ch10_overview VALUES ('TEMP-01', 23.5, NOW)
ON DUPLICATE KEY UPDATE SET value = 23.5, updated_at = NOW;
SELECT *
FROM ch10_overview
WHERE sensor_id = 'TEMP-01';
-- 次の節で同じ名前を使うため、削除します。
DROP TABLE ch10_overview;
```
### 活用パターン
| パターン | key | 再作成元 | 推奨する期限管理方法 |
|------|-----|-------------|----------------|
| 機器の最新状態 | 機器ID | TAGまたはLOG | 同じkeyを更新 |
| 短周期の集計 | 対象と時間bucket | TAGまたはLOG | bucketの置き換えまたは再構築 |
| 処理の進行状態 | ジョブID | ジョブシステム | 完了後にkeyを削除 |
| 一時クエリキャッシュ | リクエストまたはオブジェクトID | 永続テーブル | 全体を再構築 |
最新状態の更新は[データ入力と変更](../data-input-mutation/)、
一時集計は[クエリと分析](../query-analysis/)を参照してください。
## 他のテーブルを検討する場合
次の要件には、他のテーブルタイプを使用します。
| 要件 | 推奨テーブル |
|----------|-------------|
| 再起動後も必ず保持する元データ | TAGまたはLOG |
| 基準コードや機器マスターなどの永続的な参照データ | LOOKUP |
| トランザクションとリレーショナルな更新が必要な業務データ | TRANSACTION |
| 長期分析対象の時系列データ | TAG |
VOLATILEテーブルだけに保存したデータは、サーバー終了時に復旧できません。
重要なデータはTAG、LOG、LOOKUP、TRANSACTIONから適切な永続テーブルを選んで保存し、
VOLATILEテーブルはキャッシュや中間結果に使用します。
## 設計手順
VOLATILEテーブルの設計では、次の順序で決定します。
1. データを再作成できることを確認します。
2. PRIMARY KEYが必要かを決めます。
3. 想定行数とメモリ使用量を見積もります。
4. 再起動後の初期ロード手順を用意します。
5. 保持が必要な結果は、アプリケーションの明示的な書き込みで永続テーブルに保存します。
VOLATILEを永続化する専用のflushコマンドはありません。
スキーマとPRIMARY KEYの設計は[テーブル構造とスキーマ](/ja/dbms/volatile-table-usage/table-structure-schema/)、
再起動への対応は[再起動とデータ消失](/ja/dbms/volatile-table-usage/operations-lifecycle/)で説明します。
---
title: "10.2 テーブル構造とスキーマ"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/table-structure-schema/
language: ja
kind: page
---
# 10.2 テーブル構造とスキーマ
VOLATILEテーブルのPRIMARY KEY設計とスキーマ構成を説明します。
## PRIMARY KEYの設計
VOLATILEテーブルはPRIMARY KEYなしでも作成できます。
ただし、PKによる検索や`ON DUPLICATE KEY UPDATE`を使用するにはPRIMARY KEYが必要です。
### 単一のPRIMARY KEY
```sql
CREATE VOLATILE TABLE ch10_schema_state (
device_id VARCHAR(32) PRIMARY KEY,
state VARCHAR(16),
updated_at DATETIME
);
```
### 複合キーが必要な場合
複数列の組み合わせで行を一意に識別する必要がある場合は、組み合わせたキーを別のPRIMARY KEY列に格納します。
```sql
CREATE VOLATILE TABLE ch10_schema_hourly (
key_id VARCHAR(96) PRIMARY KEY,
sensor_id VARCHAR(64),
hour_ts DATETIME,
avg_value DOUBLE,
sample_cnt INTEGER
);
-- 組み合わせキーの挿入
INSERT INTO ch10_schema_hourly
VALUES ('TEMP-01:2026010110', 'TEMP-01', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 23.5, 60);
INSERT INTO ch10_schema_hourly
VALUES ('TEMP-01:2026010111', 'TEMP-01', TO_DATE('2026-01-01 11:00:00', 'YYYY-MM-DD HH24:MI:SS'), 24.1, 60);
INSERT INTO ch10_schema_hourly
VALUES ('TEMP-02:2026010110', 'TEMP-02', TO_DATE('2026-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS'), 21.0, 60);
-- 組み合わせキーの検索
SELECT sensor_id, avg_value FROM ch10_schema_hourly
WHERE key_id = 'TEMP-01:2026010110';
```
### ON DUPLICATE KEY UPDATEとの併用
```sql
-- PRIMARY KEY重複時にUPDATEを実行
INSERT INTO ch10_schema_state VALUES ('DEV-01', 'ONLINE', NOW)
ON DUPLICATE KEY UPDATE SET state = 'ONLINE', updated_at = NOW;
```
### 注意事項
- PRIMARY KEYなしでも作成できますが、PKに基づく操作(UPSERT、PK検索など)は使用できません。
- 同じPRIMARY KEYを持つ行を複数保存することはできません。`ON DUPLICATE KEY UPDATE`は、
重複行を追加する代わりに既存行を更新します。
- PRIMARY KEY列は1つだけ指定します。
## VOLATILEテーブルの設計
VOLATILEテーブルはデータをメモリだけに保持し、サーバー再起動時にデータが消失します。
テーブル定義は残るため、設計では「何を失ってもよいか」と「どのように再充填するか」を決めます。
複数セッションで共有し、再起動後に復旧する必要がない状態やキャッシュに使用します。
スキーマを決めるときは、次の項目も検討してください。
- [活用例](../overview-use-criteria/#use-cases-volatile)
- [永続性の違いとDDL](../create-alter-drop/#differences-persistence-ddl)
- [メモリのライフサイクル](../operations-lifecycle/#lifecycle-memory)
- [赤黒木インデックス](../index-performance/#index-strategy-red-black)
- [ON DUPLICATE KEY UPDATE](../data-input-mutation/#on-duplicate-key-update)
- [再起動とデータ再構築](../operations-lifecycle/#data-loss)
このページの実習テーブルは、次のように削除します。
```sql
DROP TABLE ch10_schema_hourly;
DROP TABLE ch10_schema_state;
```
---
title: "10.3 作成、変更、削除"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/create-alter-drop/
language: ja
kind: page
---
# 10.3 作成、変更、削除
VOLATILEテーブルの作成・削除と、他のテーブルタイプとの永続性の違いを説明します。
## VOLATILEテーブルの作成と管理
VOLATILEテーブルの作成・削除方法は次のとおりです。
### 作成
```sql
create volatile table vtable (id1 integer, name varchar(20));
```
### 削除
```sql
drop table vtable;
```
## 永続性の違いとDDL
VOLATILEテーブルは、他のテーブルタイプと異なりメモリにのみ存在します。
### 永続性の比較
| 項目 | VOLATILE | LOOKUP | TRANSACTION | TAG | LOG |
|------|----------|--------|-----|-----|-----|
| 保存場所 | メモリ | ディスク | ディスク | ディスク | ディスク |
| サーバー再起動後のデータ保持 | X | O | O | O | O |
| テーブル構造(DDL)の保持 | O | O | O | O | O |
### DDLの特性
VOLATILEで消失するのはデータであり、テーブル定義は他のテーブルタイプと同様に永続保存されます。
再起動後に必要なのは、再作成ではなく初期ロードです。
```sql
-- テーブル定義は一度だけ作成します。
CREATE VOLATILE TABLE ch10_ddl (
sensor_id VARCHAR(64) PRIMARY KEY,
value DOUBLE,
updated_at DATETIME
);
```
### 作成構文
基本構文は`CREATE VOLATILE TABLE テーブル名 (列定義, ...)`です。
キーによる更新や削除が必要な場合は、1つの列に`PRIMARY KEY`を指定します。
- `PRIMARY KEY`は任意です。
- PRIMARY KEY列は1つだけ指定します。
### AUTO_INCREMENT PRIMARY KEY
サーバーが数値のPRIMARY KEYを生成する場合は、単一の`LONG`または`INT64`列に`AUTO_INCREMENT`を指定します。
```sql
CREATE VOLATILE TABLE ch10_ddl_seq (
request_id LONG PRIMARY KEY AUTO_INCREMENT,
payload VARCHAR(256)
);
INSERT INTO ch10_ddl_seq(payload) VALUES('refresh');
```
PK列を省略するかNULLを指定すると、サーバーが値を生成します。
単一の`INSERT ... VALUES`では、`0..INT64_MAX`範囲のPK値を直接指定することもできます。
指定値が現在の次の自動値以上なら、次の自動値は`指定値 + 1`に進みます。小さい値を指定しても戻りません。
AUTO_INCREMENTを使用するVOLATILEテーブルでは、`INSERT ... SELECT`と`ON DUPLICATE KEY UPDATE`は使用できません。
VOLATILEテーブルはサーバー再起動時にデータが消えるため、次の自動値も1から再開します。
テーブル定義は保持されるため、再作成は不要です。
SDKでINSERT結果のIDを取得する方法は、[ROWIDとINSERT結果ID](/ja/dbms/reference/sql/rowid/)を参照してください。
### 列の追加と削除
Standard Editionでは、VOLATILEテーブルに固定長の数値ARRAY列を追加・削除できます。
```sql
ALTER TABLE ch10_ddl
ADD COLUMN (thresholds DOUBLE[2] DEFAULT [10.0, 20.0]);
ALTER TABLE ch10_ddl
DROP COLUMN (thresholds);
```
VOLATILEは既存のスカラー`ADD COLUMN`と同様に、ALTER前から存在する行をDEFAULTで書き直しません。
ARRAY DEFAULTを指定しても、既存行の新しい列は列全体がNULLになります。
この動作は、LOG、LOOKUP、TRANSACTION、TAG METADATAのバックフィル規則とは異なります。
ARRAYのサポート要素型、要素数、DEFAULT規則は、[数値ARRAY型](/ja/dbms/reference/sql/types/array/)を参照してください。
### 削除
```sql
DROP TABLE ch10_ddl;
DROP TABLE ch10_ddl_seq;
```
### 注意事項
- VOLATILEテーブルのDDL(構造定義)はデータベースに保存され、サーバー再起動後も残ります。
- データは再起動後に自動復元されないため、初期ロードスクリプト(起動時のmachsql実行など)を構成する必要があります。
---
title: "10.4 データ入力と変更"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/data-input-mutation/
language: ja
kind: page
---
# 10.4 データ入力と変更
VOLATILEテーブルの`INSERT`、重複キー更新、`DELETE`を、実行可能な例で説明します。
## データ入力と更新
次の例は、最後のクリーンアップ文まで順に実行できます。
最新状態のように同じキーの値を継続的に更新する場合は、`PRIMARY KEY`を定義し、`ON DUPLICATE KEY UPDATE`を使用します。
```sql
CREATE VOLATILE TABLE ch10_mutation (
id INTEGER PRIMARY KEY,
direction VARCHAR(10),
refcnt INTEGER
);
INSERT INTO ch10_mutation VALUES (1, 'west', 0);
INSERT INTO ch10_mutation VALUES (2, 'east', 0);
INSERT INTO ch10_mutation VALUES (1, 'south', 0)
ON DUPLICATE KEY UPDATE;
INSERT INTO ch10_mutation VALUES (1, 'south', 0)
ON DUPLICATE KEY UPDATE SET refcnt = 1;
SELECT * FROM ch10_mutation ORDER BY id;
```
重複キーがなければ新しい行を挿入します。重複キーがある場合、`SET`句のない構文は入力値で行全体を更新し、
`SET`句のある構文は指定した列だけを更新します。`PRIMARY KEY`自体は更新対象に指定できません。
大量取り込みAPIの初期化・バインド・エラー処理は、言語とドライバーによって異なります。
不完全なコード断片をコピーせず、[SDKと連携](/ja/dbms/development-tools-integration/)の該当ドライバーの例を使用してください。
## 条件付き更新
既存行の一部の列だけを変更する場合は`UPDATE`を使用します。
`INSERT ... ON DUPLICATE KEY UPDATE`が「なければ挿入し、あれば更新する」のに対し、
`UPDATE`は対象行が存在する場合だけ値を変更します。
VOLATILEテーブルの`UPDATE`には`WHERE`が必要です。
条件は削除と同様に`PRIMARY KEY = 値`の形式のみサポートし、他の列の条件や複合条件は使用できません。
`WHERE`を省略した全件更新もサポートしていません。
```sql
UPDATE ch10_mutation SET refcnt = refcnt + 1 WHERE id = 2;
SELECT * FROM ch10_mutation ORDER BY id;
```
`SET`句に`PRIMARY KEY`列は指定できません。
キーを変更する場合は、既存行を削除して新しいキーで再入力します。
## データの削除
条件付き削除は`PRIMARY KEY = 値`の形式のみサポートします。
他の列の条件や複合条件は使用できません。
```sql
DELETE FROM ch10_mutation WHERE id = 2;
SELECT * FROM ch10_mutation ORDER BY id;
DROP TABLE ch10_mutation;
```
テーブル定義を保持したまま全行を削除するには、`DELETE FROM テーブル名`のようにWHEREを省略します。
スキーマも初期化する場合は、DROP後に再作成します。
サーバーを再起動するとデータだけが消え、テーブル定義は残るため、再作成ではなく再ロードのスクリプトを別途管理します。
---
title: "10.5 クエリと分析"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/query-analysis/
language: ja
kind: page
---
# 10.5 クエリと分析
VOLATILEテーブルのキー検索、一般条件検索、一時集計を実行可能な例で説明します。
## サンプルデータの準備
VOLATILEテーブルは、他のテーブルタイプと同様に`SELECT`文で検索します。
次の例は、最後のクリーンアップ文まで順に実行できます。
```sql
CREATE VOLATILE TABLE ch10_query (
device_id VARCHAR(64) PRIMARY KEY,
status VARCHAR(16),
value DOUBLE,
updated_at DATETIME
);
INSERT INTO ch10_query VALUES ('DEV-01', 'RUNNING', 42.5, NOW);
INSERT INTO ch10_query VALUES ('DEV-02', 'STOPPED', 0, NOW);
```
## PRIMARY KEYによる検索
キー条件は、最新状態キャッシュの単一行検索に適しています。
```sql
SELECT device_id, status, value, updated_at
FROM ch10_query
WHERE device_id = 'DEV-01';
```
## 一般条件による検索
`PRIMARY KEY`以外の列で繰り返し検索する場合は、セカンダリインデックスを検討します。
```sql
CREATE INDEX ch10_query_status_idx ON ch10_query(status);
SELECT device_id, value, updated_at
FROM ch10_query
WHERE status = 'RUNNING';
```
インデックスもメモリを使用するため、実際の検索に必要な列だけに作成します。
## 一時集計の検索
短周期の集計結果を保存すると、ダッシュボードやアラーム判定の繰り返し計算を減らせます。
```sql
CREATE VOLATILE TABLE ch10_query_summary (
summary_key VARCHAR(96) PRIMARY KEY,
sensor_id VARCHAR(64),
bucket_time DATETIME,
avg_value DOUBLE,
max_value DOUBLE,
sample_cnt LONG
);
INSERT INTO ch10_query_summary
VALUES ('TEMP-01:2026-01-01T00:00', 'TEMP-01', TO_DATE('2026-01-01 00:00:00'),
21.5, 23.0, 60);
SELECT sensor_id, bucket_time, avg_value, max_value
FROM ch10_query_summary
WHERE sensor_id = 'TEMP-01'
ORDER BY bucket_time DESC
LIMIT 10;
DROP TABLE ch10_query_summary;
DROP TABLE ch10_query;
```
集計結果を長期保持する必要がある場合は、LOGまたはTRANSACTIONテーブルに定期的にコピーします。
## クエリの注意事項
- サーバー再起動後はデータが空になるため、初期ロードの実施を先に確認します。
- キー検索が中心なら`PRIMARY KEY`を指定します。
- 範囲検索やソートで頻繁に使用する列には、セカンダリインデックスを検討します。
- 重要な元データは永続テーブルに保存し、VOLATILEはキャッシュとして使用します。
---
title: "10.6 インデックスとパフォーマンス"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/index-performance/
language: ja
kind: page
---
# 10.6 インデックスとパフォーマンス
VOLATILEテーブルのインデックス作成と選択基準を説明します。
## サポートするインデックス
`PRIMARY KEY`を宣言すると、キー検索用のインデックスが作成されます。
一般列には`REDBLACK`インデックスを追加できます。
`BITMAP`と`KEYWORD`インデックスは、VOLATILEテーブルではサポートしていません。
次の例は、作成からクリーンアップまで順に実行できます。
```sql
CREATE VOLATILE TABLE ch10_index (
id INTEGER PRIMARY KEY,
name VARCHAR(20),
status VARCHAR(16)
);
CREATE INDEX ch10_index_name_idx
ON ch10_index(name) INDEX_TYPE REDBLACK;
INSERT INTO ch10_index VALUES (1, 'west device', 'ACTIVE');
INSERT INTO ch10_index VALUES (2, 'east device', 'INACTIVE');
SELECT id, name
FROM ch10_index
WHERE name = 'west device';
DROP INDEX ch10_index_name_idx;
DROP TABLE ch10_index;
```
## 設計基準
- キーによる単一行の検索と更新には`PRIMARY KEY`を使用します。
- 一般列の等価・範囲条件を繰り返し使用する場合だけ、セカンダリインデックスを追加します。
- データだけでなくインデックスもメモリを使用するため、不要なインデックスは削除します。
- 実際のクエリ条件と行数を基準に、作成前後の応答時間とメモリを比較します。
構文の詳細は[インデックス構文](/ja/dbms/reference/sql/syntax/index-syntax/)を参照してください。
---
title: "10.7 運用とデータライフサイクル"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/operations-lifecycle/
language: ja
kind: page
---
# 10.7 運用とデータライフサイクル
VOLATILEテーブルの作成・ロード・使用・消失・再構築の手順を説明します。
## データライフサイクル
1. サーバー起動後にテーブル作成SQLを実行します。
2. 必要に応じて永続的な元データから初期データをロードします。
3. アプリケーションが検索と更新を開始します。
4. 保持が必要な結果を永続テーブルに記録します。
5. サーバーが終了するとデータが消失します。テーブル定義は残ります。
## セッション間の共有
VOLATILEテーブルはサーバー全体で共有されます。
あるセッションが入力した行を別のセッションから検索でき、接続を終了しただけではデータは消失しません。
## 永続データとの境界
VOLATILEには、元データから再作成できる最新状態や中間結果だけを格納します。
監査記録、元のイベント、復旧できない結果は、TAG、LOG、LOOKUPまたはTRANSACTIONテーブルに保存します。
コピーSQLは、コピー元とコピー先の列、重複処理、実行周期を含む独立したジョブとして管理します。
## 再起動の手順
- テーブルの存在を確認します。再起動だけでは定義は消失しないため、通常は再作成しません。
- 永続的な元データがある場合は、定義した基準時点のデータだけをロードします。
- 想定行数と最新時刻を確認します。
- 検証後に、収集クライアントとアプリケーションの書き込みを再開します。
- 再構築に失敗した場合は、空のキャッシュでサービスが安全に動作するか確認します。
## 運用チェックリスト
- 初期ロードSQLをバージョン管理します。初回構築用の作成SQLも保存します。
- 本番アカウントと実際の接続情報で、スクリプトを事前検証します。
- 行数とメモリ上限を監視します。
- 保持が必要なデータがVOLATILEだけに残っていないか確認します。
- 再起動訓練でロードと検証の順序を確認します。
## メモリ確認とキャッシュの再構築
```sql
SELECT * FROM V$STORAGE_DC_VOLATILE_TABLE;
SELECT * FROM V$SYSMEM;
SELECT * FROM V$SESMEM;
SELECT NAME, VALUE
FROM V$PROPERTY
WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE';
```
特定の内部列名に依存せず、導入バージョンのビュー定義を確認してください。
キャッシュの再作成では行数とサンプル値を記録し、利用処理を切り替えてから、テーブル作成・初期ロード・検証の順に進めます。
失敗時には空のキャッシュでも安全に動作する必要があります。
---
title: "10.8 制約、エラー、トラブルシューティング"
url: https://docs.machbase.com/ja/dbms/volatile-table-usage/constraints-errors-troubleshooting/
language: ja
kind: page
---
# 10.8 制約、エラー、トラブルシューティング
VOLATILEテーブルの制約、発生し得るエラー、解決方法を説明します。
多くの問題は、メモリ上限、PRIMARY KEY設計、未サポートの列型、再起動後のデータ消失に起因します。
## 制約
VOLATILEテーブルでは、次の制約を考慮してください。
| 項目 | 制約 |
|------|------|
| 保存場所 | メモリ |
| 再起動後のデータ | 消失 |
| バックアップ・マウント | 未サポート |
| JSON列 | 未サポート |
| PRIMARY KEY | 任意。1つだけ指定 |
| UPDATE/DELETE | `PRIMARY KEY = 値`条件のみサポート |
| メモリ上限 | Volatile/Lookupテーブル全体のメモリ上限の影響を受ける |
```sql
-- 失敗例: VOLATILEテーブルではJSON列を使用できません。
CREATE VOLATILE TABLE ch10_err_json (
session_id VARCHAR(64) PRIMARY KEY,
payload JSON
);
```
可変的な属性が必要なら、頻繁に検索する値を通常の列に分離してください。
永続的なJSON列が必要な場合は、TRANSACTIONまたはTAGテーブルを検討します。
## メモリ不足
VOLATILEテーブルのデータとインデックスはメモリを使用します。
行数の増加や多数のインデックスによって、メモリ上限に達する場合があります。
診断は次の順序で行います。次の実習テーブルは、このページの最後で削除します。
```sql
-- 診断例の実習テーブルです。
CREATE VOLATILE TABLE ch10_diag (
device_id VARCHAR(64) PRIMARY KEY,
value DOUBLE
);
INSERT INTO ch10_diag VALUES ('DEV-01', 10.0);
-- 1. 対象テーブルの行数を確認します。
SELECT COUNT(*) FROM ch10_diag;
```
```sql
-- 2. VOLATILEテーブル全体のメモリ使用量を確認します。
SELECT *
FROM V$STORAGE_DC_VOLATILE_TABLE;
```
必要に応じて、設定の`VOLATILE_TABLESPACE_MEMORY_MAX_SIZE`を確認します。
```sql
SELECT NAME, VALUE
FROM V$PROPERTY
WHERE NAME = 'VOLATILE_TABLESPACE_MEMORY_MAX_SIZE';
```
対処方法は次のとおりです。
- 不要な行を削除します。
- キャッシュの保持範囲を縮小します。
- 使用していないインデックスを削除します。
- 重要なデータを永続テーブルに移してから、VOLATILEテーブルを再構築します。
- 運用ポリシーに合わせてメモリ上限の調整を検討します。
## PRIMARY KEY関連のエラー
`ON DUPLICATE KEY UPDATE`、[PKによるUPDATE](../data-input-mutation/#volatile-primary-key-update)、
PKによるDELETEを使用するにはPRIMARY KEYが必要です。
```sql
CREATE VOLATILE TABLE ch10_err_device (
device_id VARCHAR(64) PRIMARY KEY,
status VARCHAR(16),
updated_at DATETIME
);
```
PRIMARY KEYの値は重複できません。重複入力を更新として処理する場合は、`ON DUPLICATE KEY UPDATE`を使用します。
```sql
INSERT INTO ch10_err_device VALUES ('DEV-01', 'ONLINE', NOW)
ON DUPLICATE KEY UPDATE SET status = 'ONLINE', updated_at = NOW;
```
PRIMARY KEY列自体はUPDATEできません。キーを変更する場合は、既存行を削除して新しいキーで挿入します。
## 再起動後のデータ消失
サーバーの正常終了、異常終了、再起動時に、VOLATILEテーブルのデータは消失します。
これはエラーではなく、テーブルタイプの特性です。
問題が発生したら、次の項目を確認してください。
1. サーバーの再起動履歴を確認します。
2. VOLATILEテーブルの作成スクリプトが実行されたか確認します。
3. 初期ロードクエリが正常に実行されたか確認します。
4. 元のTAG/LOG/TRANSACTIONテーブルからキャッシュを再構築します。
```sql
SELECT COUNT(*) FROM ch10_diag;
```
結果が0の場合は、初期ロード手順を再実行します。
このページの実習テーブルは、次のように削除します。
```sql
DROP TABLE ch10_diag;
DROP TABLE ch10_err_device;
```
## トラブルシューティングのチェックリスト
- テーブルに保存したデータを再作成できるか確認します。
- PRIMARY KEYが必要な操作か確認します。
- `COUNT(*)`と`V$STORAGE_DC_VOLATILE_TABLE`で規模とメモリ使用量を確認します。
- 再起動後は初期ロードSQLを再実行します。テーブルの再作成は不要です。
- 永続保持が必要なら、VOLATILEではなくTAG、LOG、LOOKUP、TRANSACTIONテーブルを使用します。
---
title: "11. 開発とアプリケーション連携"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/
language: ja
kind: section
---
# 11. 開発とアプリケーション連携
アプリケーションの要件に合う連携方式を選び、SDK別のインストール・APIと共通の運用原則を確認します。
言語別の実装は各SDKページ、複数SDKに共通する判断基準は選択・概念・サポート範囲のページを参照します。
## 読む順序
1. [連携方式の選択](selection-integration-method/)で言語と入力方式に合うインターフェースを選びます。
2. [共通の連携概念](concepts-common/)で認証、時間値、バインディング、トランザクション、再試行を確認します。
3. [SDK機能のサポート範囲](sdk-support-scope/)で必要な機能の実際のサポート状況を比較します。
4. 該当言語のSDKページでインストール、接続、実行コードを確認します。
5. [データの入力とエクスポート](data-input-load-export/)で作業別の手順を適用します。
SQLのROWIDの意味は[ROWID](../reference/sql/rowid/)を参照してください。
Machbase DBMS 8.7.0のARRAYの部分入力は
[Sparse ARRAYと選択列Append API](data-input-load-export/array-append/)を参照してください。
## SDK別リファレンス
| 環境 | ドキュメント |
|---|---|
| C/C++ネイティブまたはODBC | [Machbase SQLCLIとODBC](cli-odbc/) |
| Java・Spring | [JDBC](jdbc/) |
| Python | [Python](python/) |
| Node.js・TypeScript | [Node.js / TypeScript](node-js-typescript/) |
| C#・VB.NET | [.NET Connector](net-connector/) |
| Goネイティブ・`database/sql` | [Go](go/) |
## 共通の接続情報
| 項目 | デフォルト値 | 説明 |
|---|---|---|
| HOST | `127.0.0.1` | Machbaseサーバーのホスト名またはIP |
| PORT | `5656` | Machbaseサーバーポート(`machbase.conf`の`PORT_NO`) |
| USER | `SYS` | ユーザーID |
| PASSWORD | `MANAGER` | ユーザーパスワード |
本番環境では専用ユーザーと必要最小限の権限を使用します。アカウントと認証設定は
[アカウント、権限、アクセス制御](../security-access-control/)を参照してください。
## 既存のサポート範囲リンク
NULL・PRIMARY KEYメタデータ、ROWID、Append、AUTH KEYのSDK別サポート状況は
[SDK機能のサポート範囲](sdk-support-scope/)で確認してください。
---
title: "11.1 連携方式の選択"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/selection-integration-method/
language: ja
kind: section
---
# 11.1 連携方式の選択
プロジェクトの言語、入力特性、デプロイ環境に合う連携方式を選択します。
## 選択基準
| 要件 | 優先して検討する方式 |
|----------|------------------|
| C/C++ネイティブのコレクター | SQLCLI |
| ODBCマネージャー・DSNベースのアプリケーション | ODBC |
| Java・Spring | JDBC |
| Pythonによる分析・自動化 | `machbaseapi` |
| C#・VB.NET | .NET Connector |
| Goのコレクター・サービス | v2の`database/sql`。旧v1ではネイティブ`machgo`も使用可能 |
| Node.js・TypeScriptバックエンド | `@machbase/ts-client` |
| R分析環境 | Machbase ODBCドライバーとRODBC |
| 大きなファイルの一括入力・エクスポート | machloader、csvimport、csvexport |
| 継続的なTAG・LOGの大量入力 | 選択したSDKのAppend API |
ブラウザーから5656ポートに直接接続しません。バックエンドでクエリを実行し、必要な結果のみを渡します。
## 決定手順
1. アプリケーションの言語で保守可能な公式ドライバーを選びます。
2. 5656ポートへの接続、OSとランタイムの互換性を確認します。
3. SQL、プリペアドステートメント、Append、トランザクションの必要な機能を決めます。
4. [SDK機能のサポート表](../sdk-support-scope/)で実際のサポート状況を確認します。
5. サンプルデータでタイムスタンプ、NULL、数値、文字列の往復を検証します。
6. 目標の行サイズ・同時接続数・バッチサイズで負荷テストします。
Appendのサポートだけでドライバーを決定しません。フラッシュ遅延、サーバーのエラー処理応答、再接続、
失敗行の処理まで実際のSDKで確認します。TRANSACTION DMLには明示的トランザクションのサポート範囲を
確認し、TAG・LOGのAppendを同じロールバック単位とは考えないでください。
## トピック別の詳細ドキュメント
| 内容 | 詳細ドキュメント |
|------|------|
| SDKのインストール・接続・API・完全なコード | 本章のSDK別ページ |
| 共通の認証・バインディング・トランザクション・再試行 | [共通の連携概念](../concepts-common/) |
| SDK別の機能サポート状況 | [SDK機能のサポート範囲](../sdk-support-scope/) |
| SQL・設定・コマンドラインの詳細 | [第16章 リファレンス](/ja/dbms/reference/) |
| 入力・エクスポート方式の選択 | [データの入力とエクスポート](../data-input-load-export/) |
連携方式を選んだら、該当SDKページのインストールと接続例を実行します。
機能のサポート状況は、ドキュメントに記載されたバージョンと実際の配布成果物を合わせて確認します。
---
title: "11.2 共通の連携概念"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/concepts-common/
language: ja
kind: section
---
# 11.2 共通の連携概念
ドライバーや言語に関係なく適用される、接続、バインディング、トランザクション、大量入力、エラー処理の
原則を説明します。SDK別の関数名と完全なコードは、本章のSDK別ページを参照してください。
## 接続文字列と認証
接続にはホスト、ネイティブポート、ユーザー、認証情報を使用します。デフォルトポートは`5656`ですが、
デプロイ環境の`machbase.conf`設定を確認してください。
| 項目 | 確認事項 |
|------|-----------|
| ホスト・ポート | アプリケーションの実行場所からTCP接続できるか |
| ユーザー | 対象データベースとテーブルに必要な最小限の権限 |
| パスワード | 環境変数またはシークレット管理システムで注入 |
| データベース | SDKが初期データベースの選択をサポートするか |
| タイムアウト | 接続・コマンド・読み取り制限をワークロードに合わせて設定 |
| タイムゾーン | SDKとサーバーがサポートするオプション名と適用範囲 |
例の`SYS`/`MANAGER`はローカル検証用です。本番アプリケーションには専用アカウントを作成し、
ソース、コマンド履歴、ログにパスワードを記録しません。
AUTH KEYは、パスワードの代わりに秘密鍵でチャレンジに署名する方式です。鍵形式、ファイル権限、
SDK別オプションは[AUTH KEY認証](/ja/dbms/security-access-control/authentication-auth-key/)と
該当ドライバーのドキュメントを合わせて確認します。
接続プールを使用する場合は、返却した接続の現在のデータベース、セッション設定、開いた文が
次のリクエストに影響しないよう、初期化動作を検証します。
## タイムゾーンと時間値
Machbaseの`DATETIME`はナノ秒精度をサポートします。アプリケーションでは時間値の意味と表現を
分けて管理します。
- 収集時刻の基準タイムゾーン(UTCまたは業務地域)を明示します。
- 文字列をバインドする際は、形式とタイムゾーンをともに固定します。
- エポック値を渡す際は、SDKが要求する単位が秒、ミリ秒、マイクロ秒、ナノ秒のどれかを確認します。
- 検索文字列のタイムゾーンは、接続オプションや`TO_CHAR()`など実際の使用経路で往復テストします。
- 業務規則で`NOW`と`SYSDATE`を混用せず、必要な意味をSQLリファレンスで確認します。
文字列の往復検証では、同じ接続で入力値、検索値、タイムゾーン変更後の検索値を比較します。
関数の詳細は[SQL関数](/ja/dbms/reference/sql/functions/functions-full/)を参照してください。
## プリペアドステートメント
プリペアドステートメント(prepared statement)はSQLの構造と値を分離し、同じSQLを繰り返し
実行する際に使用します。
```text
INSERT INTO sensor_data VALUES (?, ?, ?)
SELECT value FROM sensor_data WHERE name = ? AND time >= ?
```
文を準備した接続と現在のデータベースが変わっていないか確認し、使用後に閉じます。
文キャッシュを提供するSDKでは、キャッシュ範囲、項目の削除ポリシー、データベース切り替え時の
初期化動作を確認します。
CTE、LIMITなど構文の位置によってはパラメータープレースホルダーが許可されない場合があります。
構文エラーが発生したら、値を文字列として連結する前に
[Named Bind Parameter](/ja/dbms/reference/sql/syntax/named-bind-parameter-syntax/)と
該当SDKのプレースホルダーのサポート範囲を確認します。
## パラメーターバインディング
| 値の種類 | 推奨方式 |
|---------|-----------|
| 整数・実数 | 言語の固定幅型とSQL型の範囲を合わせる |
| 文字列 | エンコーディングと最大長を確認 |
| DATETIME | SDKの時間オブジェクトまたは明示されたエポック単位を使用 |
| NULL | 言語別のNULL表現とSQL型をともに指定 |
| DECIMAL | 文字列変換よりSDKの正確な固定小数点型を優先 |
| バイナリ・IP | SDKが要求するバイト配列または専用型を使用 |
位置指定のプレースホルダー`?`は出現順に値をバインドします。名前付きプレースホルダー`:name`は
対応するサーバーとSDKでのみ使用し、同名の繰り返し処理規則を確認します。識別子やSQLキーワードは
値パラメーターとしてバインドできないため、許可リストで検証してからSQLを組み立てます。
## DMLの影響行数
`INSERT`、`UPDATE`、`DELETE`の後はSDKが返す影響行数を確認します。成功応答だけで業務対象が
実際に変更されたと考えないでください。
- 単一行の変更では期待値が1か確認します。
- 0件の場合、条件に一致する行がないか、すでに同じ変更が反映されているか確認します。
- 権限不足や非サポートのDMLでは、影響行数とは別にエラーコードと例外を確認します。
- 一括変更では、実行前に同じ条件の`COUNT(*)`で範囲を確認します。
- AppendではSQLの影響行数の代わりに、close・サーバー処理応答の成功件数と失敗件数を確認します。
## トランザクション
明示的な`BEGIN`、`COMMIT`、`ROLLBACK`はTRANSACTIONテーブルのリレーショナルDMLで使用します。
LOG・TAGのAppendを同じロールバック単位とは考えないでください。
1. 使用するSDKがトランザクションAPIを提供するか確認します。
2. 提供しない場合は、サポートされるSQL制御文を同じ接続で実行します。
3. エラー時にロールバックして接続を再利用できるか確認します。
4. 接続プールへの返却前に未完了のトランザクションが残らないようにします。
5. 複数のテーブルタイプを混在させる作業では、各文のコミット範囲を事前に検証します。
完全なSQL例は
[TRANSACTIONテーブルのトランザクション](/ja/dbms/rdb-table-usage/transaction/)を参照してください。
## Append APIとバッチ
入力方式の選択と結果確認項目は[データの入力とエクスポート](../data-input-load-export/)、
クライアント・テーブルタイプ別のAppendの利用条件は
[SDK Appendサポート表](../sdk-support-scope/#append-table-type-matrix)で扱います。
Append接続は通常のクエリ接続と分け、フラッシュ・クローズと失敗行を確認します。
## エラー処理と再試行
エラーは、接続、認証・権限、SQL・スキーマ、データ、リソース不足に分類します。
- 接続切断と一時的なタイムアウトだけを、回数を制限し待機時間を設けて再試行します。
- 認証失敗、権限不足、構文エラー、型エラーは、修正前に自動再試行しません。
- 再試行前に文・カーソル・Appendハンドルと接続を解放します。
- INSERTの再試行では業務キーや重複処理ポリシーで冪等性を確保します。
- サーバーのエラーコードとメッセージは記録し、認証情報と機密の生データは除去します。
- 接続プール内でエラーになった接続は、有効性検査後に返却するか破棄します。
運用エラーの分類と診断手順は[トラブルシューティング](/ja/dbms/troubleshooting/)を参照してください。
---
title: "11.3 SDK機能のサポート範囲"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/sdk-support-scope/
language: ja
kind: section
---
# 11.3 SDK機能のサポート範囲
アプリケーションの要件に合うSDKを選択できるように、機能別のサポート状況とAPIエントリーポイントを
比較します。インストール、接続、関数、実行コードは各SDKページを参照してください。
初めてSDKを選ぶ場合は[連携方式の選択](../selection-integration-method/)を先に読み、
このページで必要な機能と正確なAPI経路を照合します。
Goの表にある「ネイティブ」は、確認基準がv1.8.4の旧`machgo` APIを指します。
[Go SDK](../go/)はv2の`database/sql` APIを説明しており、v2では旧`machgo`は提供されません。
v1の確認済み機能や最小バージョンをv2へそのまま適用せず、以下のARRAY・選択列Appendなどの
v2固有の確認基準と区別してください。
## NULL許容性のメタデータ
MachbaseはSELECT結果列のNULL許容性を`NO_NULLS`、`NULLABLE`、`UNKNOWN`で区別します。
アプリケーションは`NULLABLE`と`UNKNOWN`の両方をNULL処理の対象とします。
| SDK | 取得方法 |
|---|---|
| JDBC | `ResultSetMetaData.isNullable()` |
| Python | `cursor.description[i][6]` |
| Goネイティブ | `api.Column.Nullability` |
| Go `database/sql` | `Rows.ColumnTypeNullable()` |
| Node.js | `ColumnMeta.nullable` |
| .NET | `GetSchemaTable()`の`AllowDBNull` |
| SQLCLI・ODBC | ディスクリプターのnullable属性 |
式、集計、VIEW、JOINの結果は`UNKNOWN`になる場合があります。直接の列のスキーマ制約と
検索結果メタデータを同一と考えないでください。
## PRIMARY KEYメタデータ
| SDK | 結果列 | テーブルカタログ |
|---|:---:|:---:|
| JDBC | O | `DatabaseMetaData.getPrimaryKeys()` |
| Python | O | カタログSQL |
| Goネイティブ | O | カタログSQL |
| Go `database/sql` | 標準APIなし | カタログSQL |
| Node.js | O | カタログSQL |
| .NET | O | カタログSQL |
| ODBC | 別の結果APIなし | `SQLPrimaryKeys()` |
式・集計・外部JOINのNULL補完側は、元の列のPK属性をそのまま伝達しない場合があります。
## INSERT結果のROWID
Machbase 8.7.0 Standard Editionでは、成功した単一の`INSERT ... VALUES`が対応SDKにROWIDを
提供できます。
| SDK・ツール | 確認方法 | 値がない場合 |
|---|---|---|
| machsql | `SHOW LAST ROWID` | `NULL` |
| Machbase SQLCLI | `SQLGetGeneratedRowID()` | `SQL_NO_DATA` |
| 標準ODBC | 専用の標準APIなし | - |
| JDBC | `Statement.getGeneratedKeys()` | 空の`ResultSet` |
| Python | `cursor.lastrowid` | `None` |
| .NET | `MachCommand.RowId` | `null` |
| Go `database/sql` | `Result.LastInsertId()` | エラー |
| Goネイティブ | 非サポート | - |
| Node.js | 実行結果の`rowId` | `undefined` |
バッチ、`executemany()`、Append、loader、`INSERT ... SELECT`、UPSERTは単一のROWIDを返しません。
SQLの意味とテーブルごとの制約は[ROWID](/ja/dbms/reference/sql/rowid/)を参照してください。
## Append APIとテーブルタイプ
| API経路 | LOG | TAG | LOOKUP | VOLATILE | TRANSACTION | 基準 |
|---|:---:|:---:|:---:|:---:|:---:|---|
| SQLCLI `SQLAppend*`拡張 | O | O | O | O | O | TRANSACTIONはStandard |
| JDBC `MachStatement.executeAppend*` | O | O | O | O | O | NFX cce422dのソース・テスト |
| Python 2.4 `append*` | O | O | O | O | O | NFX cce422dのソース・テスト |
| .NET `MachAppendWriter` | O | O | O | O | O | NFX cce422dのプロバイダー |
| Go v1.8.4ネイティブ`Appender` | O | O | X | X | O | TRANSACTIONはStandard |
| Go `database/sql`標準API | X | X | X | X | X | `sql.Conn.Raw()`拡張はネイティブ仕様 |
| Nodeソースの`appendBatch()` | O | △ | △ | △ | O | NFX cce422dのソースビルド |
| Nodeソースの`appendOpen()` | O | O | △ | △ | △ | 汎用native/fallback、テーブル別の検証が必要 |
標準クエリ接続とAppendハンドルのライフサイクルを区別し、close・flushの結果を確認します。
`O`は該当ソース・テストで確認した範囲、`△`は汎用経路だけがあり、テーブル別の回帰検証がさらに
必要な範囲です。Append拡張は標準ODBCや`database/sql`の機能ではありません。
### ARRAYと選択列Append
Machbase DBMS 8.7.0のARRAYのサポート範囲は次のとおりです。
| SDK | 密なARRAYの検索・入力 | スパースARRAY | 選択列Append |
|---|:---:|:---:|:---:|
| SQLCLI・C++ | O | O | O |
| Machbase ODBC拡張 | O | O | O |
| JDBC | O | O | O |
| Python | O | O | O |
| Node.js | O | O | O |
| .NET full/legacyプロバイダー | O | O | O |
| Go | v2 mainソース | v2 mainソース | v2 mainソース |
Machbase DBMS 8.7.0サーバーとARRAY機能を含むSDKビルドを合わせて使用します。ARRAYのSQL要素位置と
Machbase専用SDKの位置は0始まりのインデックスです。既存の全行スカラーAppend APIは維持されます。
Node.jsのprepared代替経路も`SparseArray`をサポートします。Goは
[`neo-client` PR #17](https://github.com/machbase/neo-client/pull/17)以降のv2 mainソースを
使用する必要があり、公開v2リリースが指定されるまでは公開モジュールのバージョンだけでサポートを
判断しません。入力方式とAPIの詳細は
[Sparse ARRAYと選択列Append API](../data-input-load-export/array-append/)を参照してください。
## AUTH KEY
| SDK・ツール | サポート |
|---|:---:|
| machsql、Machbase SQLCLI、ODBC、JDBC | O |
| Goネイティブ、Go `database/sql` | O(neo-client v1.5.0+) |
| Python、Node.js、.NET | X |
鍵の生成・登録・交換は[AUTH KEY認証](/ja/dbms/security-access-control/authentication-auth-key/)、
接続オプションは対応SDKページを参照してください。
## トランザクション、prepare、bind
| SDK | トランザクションAPI | サーバー側prepare | 名前付きbind API |
|---|:---:|:---:|:---:|
| JDBC | O | O | △(Machbase拡張) |
| Python | X | O | O |
| Goネイティブ | △ | O | O |
| Go `database/sql` | O | O | O |
| .NET | X | X | △ |
| Node.js | X | O | O |
| SQLCLI | △ | O | O |
| ODBC | △ | O | 位置指定bind |
プリペアドステートメントとパラメーターバインディングはトランザクションのサポートとは別です。
プレースホルダーの構文は
[Named Bind Parameter](/ja/dbms/reference/sql/syntax/named-bind-parameter-syntax/)を参照してください。
Machbase 8.7.0 Standard EditionのTAGデータUPDATEは、各SDKの既存の位置指定・名前付きAPIで
NAMEとBASETIMEの条件値をバインドできます。NFX #4127の回帰テストはC/C++ SQLCLI、
Go `database/sql`、JDBC、Node.js、Python、.NETの経路を検証します。ODBCは個別のSDK回帰
マトリクスには含まれず、`?`または名前付きSQLのプレースホルダーを標準`SQLBindParameter()`の
位置番号でバインドします。TAG UPDATEの条件仕様は
[TAGデータUPDATEのバインド](/ja/dbms/reference/sql/syntax/dml-syntax/tag-data-update-syntax/#tag-data-update-predicate-bind)を
参照してください。
トランザクション列の`△`は、専用オブジェクトの代わりに同じ接続でトランザクションSQLを直接実行する
経路です。名前付きbind列の`△`は、標準の名前付きバインディングAPIではなく、ドライバー拡張、または
クライアントが値をSQLリテラルに変換する経路を表します。
## 最小確認バージョンと出所
| SDK | 本ドキュメントの確認基準 |
|---|---|
| SQLCLI・JDBC・Python | NFX `cce422d2972`、Pythonパッケージ2.4 |
| Node.js | NFX `cce422d2972`のソースビルド(`package.json` 1.0.1) |
| .NET | Uni 8.0.55、limited 3.1.3、full 3.2.2 |
| Go | 公開済みneo-client v1.8.4、AUTH KEYはv1.5.0+、データベース選択はv1.8.3+ |
NFX cce422dのNode機能の一部は、公開npm 1.0.1の配布後に追加されました。レジストリパッケージの
バージョン文字列だけで同じ機能を想定せず、配布成果物のコミット出所を確認するか、NFXソースビルドを
使用します。
ARRAYと選択列Appendの確認基準は、NFX
`655d1333870313c4951698b89c9a3c9ada11d630`とマージコミット
`f756986c4836982723e2aa7727ec05b7e05e9707`です。サーバーはMachbase DBMS 8.7.0、クライアントは
該当変更以降の検証済みSDK成果物を基準に判断します。
## SDKリファレンス
| SDK | 詳細ドキュメント |
|---|---|
| Machbase SQLCLI・ODBC | [SQLCLIとODBC](../cli-odbc/) |
| JDBC | [JDBC](../jdbc/) |
| Python | [Python](../python/) |
| Node.js / TypeScript | [Node.js / TypeScript](../node-js-typescript/) |
| .NET Connector | [.NET Connector](../net-connector/) |
| Go | [Go](../go/) |
---
title: "11.4 Machbase SQLCLIとODBC"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/cli-odbc/
language: ja
kind: section
---
# 11.4 Machbase SQLCLIとODBC
Machbase SQLCLIはC/C++アプリケーションで使用する呼び出しレベルインターフェース(Call-Level
Interface)です。ODBCドライバーは標準ODBCアプリケーションで使用します。両者は環境・接続・文の
ハンドルを使用する実行フローを共有し、SQLCLIには高速Append用の拡張関数が追加されています。
## 選択基準
| 要件 | インターフェース |
|----------|------------|
| MachbaseインストールパッケージとともにC/C++アプリケーションを開発 | SQLCLI |
| 汎用ODBCツールまたはドライバーマネージャーを使用 | ODBC |
| Append拡張APIによる大量入力 | SQLCLI |
| 標準SQLの実行と結果の取得 | SQLCLIまたはODBC |
## ヘッダーとライブラリ
インストールディレクトリで次のファイルを確認します。
```bash
test -f "$MACHBASE_HOME/include/machbase_sqlcli.h"
test -f "$MACHBASE_HOME/lib/libmachbasecli_dll.so"
```
Linuxでの動的リンクの例です。
```bash
gcc cli_quickstart.c -I"$MACHBASE_HOME/include" -L"$MACHBASE_HOME/lib" -lmachbasecli_dll -o cli_quickstart
LD_LIBRARY_PATH="$MACHBASE_HOME/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" MACHBASE_PASSWORD='your-password' ./cli_quickstart
```
本番ビルドは、インストールパッケージの`install/machbase_env.mk`とプラットフォーム別の
リンカー設定に基づいて構成します。
## 接続文字列
SQLCLIの基本的な接続文字列は次のキーを使用します。
```text
SERVER=127.0.0.1;PORT_NO=5656;UID=APP_USER;PWD=secret;CONNTYPE=1
```
ODBCデータソースを使用する場合はDSN、アカウント、パスワードを指定します。
```text
DSN=MACHBASE;UID=APP_USER;PWD=secret
```
マルチデータベースの初期値をサポートするドライバーでは`DATABASE`または`DBNAME`を使用できます。
実際に配布されたドライバーのサポート状況を確認し、接続後に`SELECT CURRENT_DATABASE()`で
選択結果を検証します。
## クイックスタート
次のプログラムは5656ポートに接続してシステムテーブルのクエリを実行し、全ハンドルを解放します。
パスワードは環境変数で渡します。
```c
#include
#include
#include
int main(void)
{
SQLHENV env = SQL_NULL_HENV;
SQLHDBC dbc = SQL_NULL_HDBC;
SQLHSTMT stmt = SQL_NULL_HSTMT;
char conn[512];
const char *password = getenv("MACHBASE_PASSWORD");
if (password == NULL) {
fputs("MACHBASE_PASSWORD is required\n", stderr);
return 2;
}
snprintf(conn, sizeof(conn),
"SERVER=127.0.0.1;PORT_NO=5656;"
"UID=SYS;PWD=%s;CONNTYPE=1", password);
if (SQLAllocEnv(&env) != SQL_SUCCESS) {
return 3;
}
if (SQLAllocConnect(env, &dbc) != SQL_SUCCESS) {
SQLFreeEnv(env);
return 4;
}
if (SQLDriverConnect(
dbc, NULL, (SQLCHAR *)conn, SQL_NTS,
NULL, 0, NULL, SQL_DRIVER_NOPROMPT) != SQL_SUCCESS) {
SQLFreeConnect(dbc);
SQLFreeEnv(env);
return 5;
}
if (SQLAllocStmt(dbc, &stmt) != SQL_SUCCESS) {
SQLDisconnect(dbc);
SQLFreeConnect(dbc);
SQLFreeEnv(env);
return 6;
}
if (SQLExecDirect(
stmt, (SQLCHAR *)"SELECT COUNT(*) FROM V$TABLES",
SQL_NTS) != SQL_SUCCESS) {
SQLFreeStmt(stmt, SQL_DROP);
SQLDisconnect(dbc);
SQLFreeConnect(dbc);
SQLFreeEnv(env);
return 7;
}
puts("query succeeded");
SQLFreeStmt(stmt, SQL_DROP);
SQLDisconnect(dbc);
SQLFreeConnect(dbc);
SQLFreeEnv(env);
return 0;
}
```
失敗原因を出力する必要があるアプリケーションは、`SQLGetDiagRec()`または既存コードの
`SQLError()`でSQLSTATE、ネイティブエラーコード、メッセージを読み取ります。
## 標準的な実行フロー
1. 環境ハンドルと接続ハンドルを割り当てます。
2. `SQLDriverConnect()`または`SQLConnect()`で接続します。
3. 文ハンドルを割り当てます。
4. `SQLPrepare()`と`SQLExecute()`、または`SQLExecDirect()`でSQLを実行します。
5. SELECT結果は`SQLBindCol()`と`SQLFetch()`で読み取ります。
6. 文、接続、環境の順にリソースを解放します。
入力値は文字列として連結せず、`SQLBindParameter()`でバインドします。NULL許容性は
`SQLDescribeCol()`の最後の引数、または`SQLColAttribute(..., SQL_DESC_NULLABLE, ...)`で確認します。
## Named Bind Parameter
サーバーとドライバーが名前付きパラメーターをサポートする場合、`:name`プレースホルダーを使用し、
`SQLBindParameterByName()`でバインドできます。同じ名前が複数回現れると1つの値が全位置に適用されます。
共通の制約と例は
[Named Bind Parameter](/ja/dbms/reference/sql/syntax/named-bind-parameter-syntax/)を参照してください。
サポートを確認できない環境では、標準の`?`プレースホルダーと`SQLBindParameter()`を使用します。
## INSERT結果のROWID
Standard Editionで単一の`INSERT ... VALUES`が成功した後、生成されたROWIDが必要な場合は
次の方法を使用します。
- SQLCLI拡張: `SQLGetGeneratedRowID()`
- 標準ODBC: 生成ROWID専用の標準APIなし
バッチ、Append、`INSERT ... SELECT`、UPSERTで同じ戻り値を想定しないでください。詳細な範囲は
[ROWIDとINSERT結果ID](/ja/dbms/reference/sql/rowid/)を参照してください。
## Append拡張API
高速入力は通常の文と分けたAppendフローを使用します。
| 段階 | 主な関数 |
|------|-----------|
| オープン | `SQLAppendOpen()`、選択列は`SQLAppendOpenColumns()`/`W()` |
| 1行の入力 | `SQLAppendDataV2()`または対応バージョンのAppend関数 |
| バッチ入力 | `SQLAppendBatch()` |
| サーバーへの反映 | `SQLAppendFlush()` |
| エラーコールバック | `SQLAppendSetErrorCallback()` |
| クローズ | `SQLAppendClose()` |
Append行の列順序と型は、対象テーブルのスキーマと完全に一致する必要があります。文字列、バイナリ、
IP、DATETIME、NULLの表現は、インストール済み`machbase_sqlcli.h`の`SQL_APPEND_PARAM`定義に
基づいて記述します。エラーコールバックでは失敗行とサーバーエラーを記録しますが、パスワードや機密の
生データはログに残しません。
有効なAppendハンドルがある接続は通常のクエリと共有せず、close結果の成功・失敗件数を確認します。
## マルチスレッドとリソース管理
- スレッドごとに接続と文を分けます。
- 1つの文またはAppendハンドルを複数スレッドで同時に使用しません。
- すべてのエラー経路でもハンドルを逆順に解放するよう、後処理関数を用意します。
- 再試行前に、前の接続とAppendの状態が完全に閉じているか確認します。
- 大量入力では成功件数と失敗件数の両方を記録します。
## API詳細の確認
関数プロトタイプ、定数、構造体は、インストール済みの
`$MACHBASE_HOME/include/machbase_sqlcli.h`が該当ライブラリと一致する基準です。
サンプルを別バージョンのヘッダーと混用せず、コンパイル・リンク・5656接続のテストを
デプロイパイプラインに含めます。
## DECIMAL Append
`SQLAppendDataV2()`と`SQLAppendBatch()`で`DECIMAL`または`NUMERIC`値を入力する際は、
32バイトの不透明型`SQL_APPEND_NUMERIC`と公開生成関数を使用します。
アプリケーションで内部バイトを直接作成・変更しません。
| 入力 | 関数 |
|---|---|
| UTF-8の数値文字列 | `SQLAppendNumericFromString()` |
| 符号付き・符号なし整数 | `SQLAppendNumericFromInt64()`、`SQLAppendNumericFromUInt64()` |
| `SQL_NUMERIC_STRUCT` | `SQLAppendNumericFromSQLNumeric()` |
| NULL | `SQLAppendNumericSetNull()` |
正確な値を保持するには、文字列または`SQL_NUMERIC_STRUCT`を優先します。型配列には
`SQL_APPEND_TYPE_NUMERIC`または`SQL_APPEND_TYPE_DECIMAL`を指定し、対象列の精度とスケールに
基づいてオーバーフローと丸めを確認してください。
## ARRAYと選択列Append
Machbase DBMS 8.7.0は、`SQL_MACHBASE_ARRAY_DESC`による型付きARRAYの検索・バインドと、
`SQL_MACHBASE_SPARSE_ARRAY_DESC`によるスパース入力をサポートします。通常のOpenでもARRAY列に
スパースディスクリプターを渡せます。
```c
SQLAppendOpen(statement, (SQLCHAR *)"ARRAY_APPEND_FULL_EXAMPLE", 0);
row[0].mLong = 1;
row[1].mVar.mData = &sparse;
row[1].mVar.mLength = SQL_APPEND_SPARSE_ARRAY_DESC_LENGTH;
SQLAppendDataV3(statement, row, 2);
SQLAppendClose(statement, &success, &failure);
```
上記コードは`ID LONG, A INT32[4]`テーブルの入力順序に従います。接続・ディスクリプター・バッファの
準備とエラー処理を含む[通常Openの全体例](../data-input-load-export/array-append/#c-full-open)を
先に確認してください。旧式の`SQLAppendData(void *[])`にディスクリプターを渡す方式とは異なります。
一部の列または固定ARRAY要素だけを選択する場合は、`SQLAppendOpenColumns()`または
`SQLAppendOpenColumnsW()`を使用します。
```c
SQLCHAR *targets[] = {
(SQLCHAR *)"ID",
(SQLCHAR *)"CHANNELS[0]",
(SQLCHAR *)"CHANNELS[3]",
NULL
};
SQLAppendOpenColumns(statement, (SQLCHAR *)"SENSOR_ARRAY", targets, 0);
```
ARRAY要素の対象とスパースディスクリプターの位置は0始まりのインデックスです。列名リストの最後の要素は
`NULL`である必要があります。`SQLAppendBatch()`はARRAYをサポートしません。
ディスクリプター定義、配列全体のNULLと要素NULLの処理、直接ODBCハンドルの制約は
[Sparse ARRAYと選択列Append API](../data-input-load-export/array-append/)を参照してください。
---
title: "11.5 JDBC"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/
language: ja
kind: section
---
# 11.5 JDBC
Machbase JDBCドライバーはJava 8を基準にJDBC 4.2の主要APIを提供します。標準JDBC APIで
サーバーに接続し、PreparedStatement、型指定の検索とバインディング、データベースメタデータ、
ローカルトランザクション、接続プールを使用できます。
| 項目 | 値 |
|------|----|
| Javaバイトコード基準 | Java 8 |
| ドライバーが報告するJDBCバージョン | 4.2 |
| ドライバーバージョン | 3.0.0 |
| JDBC URL | `jdbc:machbase:///[database]` |
| `Driver.jdbcCompliant()` | `false` |
`jdbcCompliant()`の`false`はJDBC 4.2 APIのサポート状況ではなく、SQL-92 Entry Level全体への
準拠状況を示します。アプリケーションでは必要な任意機能を`DatabaseMetaData`の機能メソッドで確認します。
## マルチデータベース
URLパスまたは`database`接続プロパティで初期データベースを指定できます。
```java
String url = "jdbc:machbase://127.0.0.1:5656/factory_a";
Connection conn = DriverManager.getConnection(url, "APP_A", password);
System.out.println(conn.getCatalog());
conn.setCatalog("FACTORY_A");
```
`getCatalog()`と`setCatalog()`はサーバーの現在のデータベースと同期します。URLパスと設定プロパティを
両方指定する場合は同じ値にする必要があります。JDBCメタデータではカタログはデータベース、スキーマは
所有者です。プールされた接続の返却時に初期カタログへ復元されるか確認し、プリペアドステートメントと
Appendハンドルは作成時のデータベースに固定される点を考慮します。
## ドライバーのインストール
### JARファイルの使用
Machbaseインストールディレクトリの`machbase.jar`をクラスパスに追加します。
```bash
ls -l "$MACHBASE_HOME/lib/machbase.jar"
javac -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp.java
java -classpath ".:$MACHBASE_HOME/lib/machbase.jar" MyApp
```
JARには`META-INF/services/java.sql.Driver`が含まれています。JDBC 4.0以降の環境では
`Class.forName("com.machbase.jdbc.MachDriver")`を呼び出さなくてもドライバーが自動登録されます。
既存アプリケーションの明示的な呼び出しも引き続き使用できます。
### Maven
```xml
com.machbase
machjdbc
{{< jdbc_version >}}
```
### Gradle
```groovy
dependencies {
implementation 'com.machbase:machjdbc:{{< jdbc_version >}}'
}
```
配布成果物のバージョンは[Maven Central](https://mvnrepository.com/artifact/com.machbase/machjdbc)で
確認します。ドライバーが実行時メタデータで返す`3.0.0`と配布成果物のバージョンは、別のバージョン体系です。
## サーバーへの接続
ユーザー名とパスワードはソースコードに記録せず、環境変数やシークレット管理システムで渡します。
```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
String url = "jdbc:machbase://127.0.0.1:5656/machbasedb";
Properties properties = new Properties();
properties.setProperty("user", "SYS");
properties.setProperty("password", System.getenv("MACHBASE_PASSWORD"));
try (Connection connection =
DriverManager.getConnection(url, properties)) {
// SQLを実行します。
}
```
### 接続オプション
接続オプションは`Properties`またはURLクエリ文字列で指定します。`randomHost`は`Properties`で
指定するか、複数ホストURLの`^`区切り文字を使用します。
| オプション | 説明 |
|------|------|
| `user`, `password` | パスワード認証情報 |
| `TIMEZONE` | セッションのタイムゾーン。`+0900`形式を使用します。 |
| `randomHost` | ホスト一覧から最初の接続先をランダムに選択します。 |
| `maxStatements` | プールされた接続の最大キャッシュStatement数 |
| `CONNECTION_TIMEOUT` | ソケット接続のタイムアウト(秒)。`0`は無制限です。 |
| `SOCKET_TIMEOUT` | ソケット読み取りのタイムアウト(秒)。`0`は無制限です。 |
| `characterEncoding` | クライアントの文字エンコーディング |
| `AUTH_MODE` | `PASSWORD`または`CHALLENGE` |
| `AUTH_SIG_SCHEME` | `ECDSA`、`RSA_PKCS1_V15`、`RSA_PSS` |
| `AUTH_KEY_FILE` | PEM秘密鍵ファイルのパス |
```java
String url =
"jdbc:machbase://127.0.0.1:5656/machbasedb?TIMEZONE=+0900";
```
### 複数ホストへの接続
Machbase 8.7.0 JDBCドライバーは、1つのURLに複数ホストを指定できます。
| 選択方式 | 指定方法 | 動作 |
|-----------|-----------|------|
| 順次選択 | ホストを`,`で区切る | URLの記載順に接続を試みます。 |
| ランダム開始 | ホストを`^`で区切る | ホスト一覧から最初の接続先をランダムに選びます。 |
| ランダム開始 | `Properties`で`randomHost=true`を指定 | `,`で区切った一覧から最初の接続先をランダムに選びます。 |
次のURLは`db1`への接続に失敗すると、`db2`への接続を試みます。
```java
String url =
"jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";
```
`^`区切り文字を使用すると、最初の接続先をランダムに選択します。
```java
String url =
"jdbc:machbase://db1.example.com:5656^db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";
```
`randomHost`設定プロパティを使用する場合は、`,`でホストを区切ります。
```java
Properties properties = new Properties();
properties.setProperty("randomHost", "true");
String url =
"jdbc:machbase://db1.example.com:5656,db2.example.com:5656/" +
"machbasedb?CONNECTION_TIMEOUT=5";
```
- 1つのURLで`,`と`^`の区切り文字は併用できません。
- 接続拒否、接続タイムアウト、ソケットエラーなど接続段階のI/Oエラーが発生すると、次のホストへの
接続を試みます。すべてのホストが失敗すると`DriverManager.getConnection()`は`SQLException`を返します。
- `CONNECTION_TIMEOUT`はホストごとの接続試行に適用されます。そのため全体の接続待機時間は
ホスト数と各ホストの応答時間によって長くなる場合があります。
- `SOCKET_TIMEOUT`は接続済みソケットの読み取り待機時間を制限し、ホストの選択順序は変更しません。
複数ホストの切り替えは、新規接続または再接続時のソケット接続に適用されます。切断後に自動再接続が
成功しても、以前のStatement、PreparedStatement、ResultSetは再利用しません。実行中のSQLの成功や
安全な再実行は保証されないため、有効なトランザクションで接続エラーが発生した場合は接続を破棄し、
業務の冪等性ポリシーに従ってトランザクション全体を再実行します。
## AUTH KEY認証
公開鍵によるチャレンジ認証では、パスワードの代わりにローカルの秘密鍵でサーバーチャレンジに署名します。
```java
Properties properties = new Properties();
properties.setProperty("user", "app_user");
properties.setProperty("AUTH_MODE", "CHALLENGE");
properties.setProperty("AUTH_SIG_SCHEME", "ECDSA");
properties.setProperty(
"AUTH_KEY_FILE", "/opt/machbase/keys/app_user_ecdsa.pem");
Connection connection = DriverManager.getConnection(
"jdbc:machbase://127.0.0.1:5656/machbasedb", properties);
```
- `AUTH_MODE=CHALLENGE`では認証に`password`を使用しません。
- `AUTH_KEY_FILE`は必須です。
- `AUTH_SIG_SCHEME`を省略すると、鍵の種類に合うデフォルト署名方式を選択します。
- POSIX環境では秘密鍵ファイルの権限を`600`に制限します。
## クイックスタート
次の例はLOGテーブルに値を入力し、再検索します。
```java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class JdbcQuickStart {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.setProperty("user", "SYS");
properties.setProperty(
"password", System.getenv("MACHBASE_PASSWORD"));
try (Connection connection = DriverManager.getConnection(
"jdbc:machbase://127.0.0.1:5656/machbasedb",
properties);
Statement statement = connection.createStatement()) {
statement.execute(
"CREATE LOG TABLE jdbc_sensor " +
"(ts DATETIME, name VARCHAR(40), value DOUBLE)");
try (PreparedStatement insert = connection.prepareStatement(
"INSERT INTO jdbc_sensor VALUES (?, ?, ?)")) {
insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
insert.setString(2, "sensor-1");
insert.setDouble(3, 25.3);
insert.executeUpdate();
}
try (ResultSet result = statement.executeQuery(
"SELECT name, value FROM jdbc_sensor")) {
while (result.next()) {
System.out.printf("%s %.1f%n",
result.getString("NAME"),
result.getDouble("VALUE"));
}
}
}
}
}
```
DATETIMEにエポックナノ秒値を渡す場合は`long`を使用します。例のテーブルがすでに存在する場合は、
`CREATE LOG TABLE`を省略するか別名を使用します。
## INSERT結果のROWID
Standard Editionで単一の`INSERT ... VALUES`が成功すると、JDBC標準の生成キーAPIで入力行の
ROWIDを確認できます。
```java
String sql = "INSERT INTO jdbc_sensor VALUES (?, ?, ?)";
try (PreparedStatement insert = connection.prepareStatement(
sql, Statement.RETURN_GENERATED_KEYS)) {
insert.setLong(1, System.currentTimeMillis() * 1_000_000L);
insert.setString(2, "sensor-2");
insert.setDouble(3, 26.1);
insert.executeUpdate();
try (ResultSet keys = insert.getGeneratedKeys()) {
if (keys.next()) {
java.sql.RowId rowId = keys.getRowId("ROWID");
}
}
}
```
結果は1つの`ROWID`列と最大1行で構成されます。返すROWIDがない場合は空の`ResultSet`です。
サポート状況は`DatabaseMetaData.supportsGetGeneratedKeys()`で確認します。
バッチ、Append、`INSERT ... SELECT`、UPSERTの違いは
[ROWIDとINSERT結果ID](/ja/dbms/reference/sql/rowid/)を参照してください。
## バージョンの確認
```java
import java.sql.DatabaseMetaData;
DatabaseMetaData metadata = connection.getMetaData();
System.out.println(metadata.getDriverName());
System.out.println(metadata.getDriverVersion());
System.out.println(metadata.getJDBCMajorVersion()); // 4
System.out.println(metadata.getJDBCMinorVersion()); // 2
```
## 関連ドキュメント
| ドキュメント | 内容 |
|------|------|
| [PreparedStatementと型](./prepared-types/) | パラメーターメタデータ、名前付きbind、SQLType、NULL、型変換 |
| [ResultSet、Statement、LOB](./resultset-lob/) | 型指定の検索、ストリーム、LOB、タイムアウト、リソース管理 |
| [トランザクションと接続プール](./transaction-pooling/) | Standardのローカルトランザクション、DataSource、接続プール |
| [DatabaseMetaData](./database-metadata/) | テーブル、列、キー、インデックス、機能の検索 |
| [Append API](./append-api/) | `MachStatement`による高速入力 |
| [移行とトラブルシューティング](./migration-troubleshooting/) | 旧ドライバーからの移行、非サポート機能、エラー処理 |
---
title: "11.5.1 PreparedStatementと型"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/prepared-types/
language: ja
kind: page
---
# 11.5.1 PreparedStatementと型
PreparedStatementはSQLをサーバーでprepareし、パラメーターだけを変えて繰り返し実行します。
Machbase JDBCは標準の位置指定パラメーターと名前付き拡張パラメーターを提供します。
## ParameterMetaData
`PreparedStatement.getParameterMetaData()`で実行前にパラメーターの数と型を確認できます。
INSERT、UPDATE、SELECTで同じように使用します。
```java
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
try (PreparedStatement statement = connection.prepareStatement(
"INSERT INTO sensor_tx " +
"(id, value, created_at) VALUES (?, ?, ?)")) {
ParameterMetaData metadata = statement.getParameterMetaData();
for (int index = 1; index <= metadata.getParameterCount(); index++) {
System.out.printf(
"%d: type=%s precision=%d scale=%d nullable=%d%n",
index,
metadata.getParameterTypeName(index),
metadata.getPrecision(index),
metadata.getScale(index),
metadata.isNullable(index));
}
}
```
パラメーターのインデックスは1から始まります。0またはパラメーター数を超えるインデックスは
`SQLException`になります。precisionは型に応じて解釈します。数値型では保存バイト数ではなく、
JDBCの10進桁数を表します。DATETIMEは`java.sql.Types.TIMESTAMP`にマッピングされますが、
データベースの型名は`DATETIME`です。
## Named Bind Parameter
`:name`プレースホルダーと`MachPreparedStatement.setObject(String, Object)`はMachbase拡張です。
同じ名前が複数回現れると、その名前のすべての位置に値が適用されます。
```java
import com.machbase.jdbc.MachPreparedStatement;
try (MachPreparedStatement statement =
(MachPreparedStatement) connection.prepareStatement(
"SELECT id FROM sensor_tx " +
"WHERE id = :id OR parent_id = :id")) {
statement.setObject("id", Integer.valueOf(10));
try (ResultSet result = statement.executeQuery()) {
while (result.next()) {
System.out.println(result.getInt("ID"));
}
}
}
```
- 名前の先頭のコロンは指定・省略のどちらも可能です。
- 名前は大文字と小文字を区別します。
- 1つの文で名前付きsetterと数値インデックスsetterを混用しません。
- SQLにない名前、または名前付き・位置指定の混用はSQLState `07009`になります。
- 名前付きbindをサポートしない旧サーバーではSQLState `0A000`になります。
移植性が必要なアプリケーションは、JDBC標準の`?`と数値インデックスsetterを使用します。
共通の名前構文は[Named Bind Parameter](/ja/dbms/reference/sql/syntax/named-bind-parameter-syntax/)を
参照してください。
## Prepared SELECTの再実行
同じPreparedStatementでSELECTを繰り返し実行できます。前のResultSetを閉じて値を再バインドすると、
次の実行で新しいResultSetを返します。
```java
try (PreparedStatement statement = connection.prepareStatement(
"SELECT id, name FROM sensor_tx WHERE id = ?")) {
ResultSetMetaData metadata = statement.getMetaData();
System.out.println(metadata.getColumnCount());
for (int id = 1; id <= 2; id++) {
statement.setInt(1, id);
try (ResultSet result = statement.executeQuery()) {
while (result.next()) {
System.out.println(result.getString("NAME"));
}
}
}
}
```
Machbase JDBCは1つのStatementで複数の結果を同時に開く機能をサポートしません。各実行のResultSetを
読み取って閉じてから、次の実行を開始します。prepare段階の`ResultSetMetaData`は、Statementが
開いている間は再取得できます。
## JDBC 4.2 SQLTypeのバインディング
Java 8の`JDBCType`でパラメーターのSQL型を指定できます。
```java
import java.math.BigDecimal;
import java.sql.JDBCType;
import java.sql.Timestamp;
try (PreparedStatement statement = connection.prepareStatement(
"INSERT INTO sensor_tx " +
"(id, name, value, created_at, payload) " +
"VALUES (?, ?, ?, ?, ?)")) {
statement.setObject(1, Integer.valueOf(1), JDBCType.INTEGER);
statement.setObject(2, "sensor-1", JDBCType.VARCHAR);
statement.setObject(
3, new BigDecimal("12.3400"), JDBCType.DECIMAL, 4);
statement.setObject(
4, Timestamp.valueOf("2026-07-26 10:00:00"),
JDBCType.TIMESTAMP);
statement.setObject(5, new byte[] {1, 2, 3}, JDBCType.BINARY);
statement.executeUpdate();
}
```
不明なベンダー`SQLType`は`SQLFeatureNotSupportedException`になります。
DECIMALとNUMERICは`BigDecimal`を使用し、指定スケールに合わせてバインドします。
### SQL NULL
`setNull()`または`setObject(index, null, JDBCType)`を使用すると、対象型に合うSQL NULLが
渡されます。次の型も型付きNULLをサポートします。
- `REAL`、`BIT`、`TINYINT`、`BOOLEAN`
- `VARBINARY`、`LONGVARBINARY`、`BLOB`、`CLOB`
- `LONGVARCHAR`
符号なしパラメーターのNULLは、ParameterMetaDataに基づいてネイティブのNULL値に変換されます。
符号なし型の最大データ値より1大きい通信上のNULLセンチネルは実データとして保存できず、
その値を渡すとSQLState `22003`になります。
| Machbaseの型 | Javaの型 | データ範囲 |
|---------------|-----------|-------------|
| `USHORT` | `Integer` | 0~65534 |
| `UINTEGER` | `Long` | 0~4294967294 |
| `ULONG` | `BigInteger` | 0~18446744073709551614 |
NULLを入力する場合はセンチネル値を直接渡さず、`setNull()`を使用します。
## Boolean
`setBoolean()`と`setObject(index, value, JDBCType.BOOLEAN)`は、`true`を1、`false`を0として
渡します。文字列は大文字・小文字を問わず`true`と`false`のみ許可され、それ以外はSQLState `22018`に
なります。
## IPv4とIPv6
IPアドレス列には`MachPreparedStatement`の拡張setterを使用できます。
```java
MachPreparedStatement statement =
(MachPreparedStatement) connection.prepareStatement(
"INSERT INTO net_log(ts, src_ip, dst_ip) VALUES (?, ?, ?)");
statement.setLong(1, System.currentTimeMillis() * 1_000_000L);
statement.setIpv4(2, "192.168.1.100");
statement.setIpv6(3, "::1");
statement.executeUpdate();
```
## NULL許容性のメタデータ
`ParameterMetaData.isNullable()`は`parameterNoNulls`、`parameterNullable`、
`parameterNullableUnknown`のいずれかを返します。`parameterNullableUnknown`をNOT NULLと
解釈しないでください。SQL別の判定規則は
[NULL許容性メタデータのサポート範囲](/ja/dbms/development-tools-integration/sdk-support-scope/#support-scope-sdk-nullable-metadata)を
参照してください。
---
title: "11.5.2 ResultSet、Statement、LOB"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/resultset-lob/
language: ja
kind: page
---
# 11.5.2 ResultSet、Statement、LOB
Machbase JDBCのResultSetは前方のみの読み取り専用カーソルです。
Connection、Statement、ResultSetはtry-with-resourcesで閉じます。
```java
statement.getResultSetType(); // ResultSet.TYPE_FORWARD_ONLY
statement.getResultSetConcurrency(); // ResultSet.CONCUR_READ_ONLY
```
スクロール可能または更新可能なResultSetはサポートしません。`next()`の前、最終行の後、close後の
getter呼び出しや、範囲外の列インデックスは`SQLException`になります。
## 型指定の検索
`getObject(index, Class)`と`getObject(label, Class)`をサポートします。
```java
import java.math.BigDecimal;
import java.sql.Timestamp;
try (ResultSet result = statement.executeQuery(
"SELECT id, value, created_at FROM sensor_tx")) {
while (result.next()) {
Integer id = result.getObject("ID", Integer.class);
BigDecimal value =
result.getObject("VALUE", BigDecimal.class);
Timestamp createdAt =
result.getObject("CREATED_AT", Timestamp.class);
}
}
```
| Javaの型 | 一般的なMachbaseの型 |
|-----------|-------------------------|
| `String` | CHAR、VARCHAR、TEXT、IPV4、IPV6、JSON |
| `Short`, `Integer`, `Long` | 整数型 |
| `Float`, `Double` | 実数型 |
| `BigDecimal` | DECIMAL、NUMERIC |
| `Boolean` | BOOLEAN |
| `Timestamp`, `Date`, `Time` | DATETIME |
| `byte[]` | BINARY |
| `Blob`, `Clob` | BLOB、CLOB |
SQL NULLはオブジェクトgetterでJavaの`null`を返します。プリミティブgetterは0または`false`を返すため、
直後の`wasNull()`でSQL NULLかを確認します。非サポートの変換や対象クラスのnull指定は
`SQLException`になります。
Machbase SQLでは空文字列リテラル`''`はSQLの`NULL`です。そのため、該当結果列の
`ResultSetMetaData.isNullable()`は`columnNullable`、`getObject()`は`null`を返します。
`''''`は単一引用符1文字であり、NULLではない文字列です。
符号なし型のデフォルトのオブジェクトマッピングは次のとおりです。
| Machbaseの型 | `getObject()`の戻り値の型 |
|---------------|-------------------------|
| `USHORT` | `Integer` |
| `UINTEGER` | `Long` |
| `ULONG` | `BigInteger` |
`SHORT`は`Integer`、32ビットの`FLOAT`は`Float`オブジェクトとして返します。
BOOLEAN文字列は`true`と`false`のみ許可します。
## 文字・バイナリストリーム
`setAsciiStream()`、`setBinaryStream()`、`setCharacterStream()`は、長さを`int`、`long`で
指定するオーバーロードと、長さを指定しないオーバーロードを提供します。`setNCharacterStream()`と
`setNString()`は専用のNCHAR保存型ではなく、VARCHAR経路の別名です。
ResultSetでは次のgetterをインデックスまたは列名で使用できます。
- `getAsciiStream()`、`getBinaryStream()`
- `getCharacterStream()`、`getNCharacterStream()`
- `getNString()`
長さ指定の入力が宣言した長さより短い場合、長さが負の場合、`Integer.MAX_VALUE`を超える場合は
`SQLException`になります。現在のストリームはクライアントメモリに全体を実体化するため、
一定のメモリだけで処理する大容量ストリーミングには使用しません。
## BLOBとCLOB
LOGテーブルのBLOB/CLOB列は標準の`Blob`と`Clob`オブジェクトで検索・バインドできます。
```java
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.sql.Blob;
import java.sql.Clob;
try (PreparedStatement insert = connection.prepareStatement(
"INSERT INTO event_log (payload, message) VALUES (?, ?)")) {
insert.setBlob(1, new ByteArrayInputStream(payload));
insert.setClob(2, new StringReader(message));
insert.executeUpdate();
}
try (ResultSet result = statement.executeQuery(
"SELECT payload, message FROM event_log")) {
while (result.next()) {
Blob payloadObject = result.getBlob("PAYLOAD");
Clob messageObject = result.getClob("MESSAGE");
byte[] payloadBytes = payloadObject.getBytes(
1, (int) payloadObject.length());
String messageText = messageObject.getSubString(
1, (int) messageObject.length());
payloadObject.free();
messageObject.free();
}
}
```
`Connection.createBlob()`と`createClob()`で変更可能なオブジェクトを作成し、`setBytes()`、
`setString()`、`setBinaryStream()`、`setCharacterStream()`、`truncate()`を使用できます。
使用後は`free()`を呼び出します。
LOBの位置はJDBC標準に従い1から始まります。部分ストリームの要求範囲全体が実際の値の範囲内に
ある必要があり、末尾を超える場合は短く切り詰めて返さず、SQLState `22003`になります。
負の長さやJava配列で表現できない長さは`HY090`です。`free()`後のオブジェクト再使用は
`SQLException`になります。
LOBは値全体をクライアントメモリに実体化します。数百MiB以上の値を一定のメモリで処理する
ストリーミングLOB実装ではありません。
## ResultSetメタデータ
`ResultSetMetaData.isNullable()`でSELECT結果列のNULL許容性を確認します。
```java
ResultSetMetaData metadata = result.getMetaData();
int nullable = metadata.isNullable(columnIndex);
```
`columnNullableUnknown`はNOT NULLを意味しません。テーブル列の制約は
`DatabaseMetaData.getColumns()`、PRIMARY KEYは`DatabaseMetaData.getPrimaryKeys()`で別途確認します。
## 行数とフェッチ設定
JDBC 4.2のlarge update APIは更新件数を`long`で返します。
```java
long count = statement.executeLargeUpdate(
"DELETE FROM sensor_tx WHERE id < 100");
long[] counts = statement.executeLargeBatch();
```
`setLargeMaxRows()`と`getLargeMaxRows()`も使用できます。`setMaxRows()`または
`setLargeMaxRows()`はResultSetで取得する最大行数を制限しますが、Statementの`fetchSize`値は
変更しません。
## Statementのライフサイクル
- `closeOnCompletion()`を設定すると、最後のResultSetが閉じる際にStatementも閉じます。
- 1つのStatementの前のResultSetは、再実行前に閉じます。
- コミットはResultSetを閉じますが、StatementとPreparedStatementは再利用できます。
- 1つのResultSetの`next()`とgetterを複数スレッドで同時に呼び出しません。
## キャンセルとクエリタイムアウト
`Statement.cancel()`は現在実行中の文を別セッションからキャンセルします。実行中の文がなければ
何もせず、PreparedStatementのバインドとメタデータは維持されます。
`setQueryTimeout(seconds)`が期限切れになると、`SQLTimeoutException`とSQLState `HYT00`が
発生します。同じStatementは例外処理後に次のクエリで再利用できます。
前の実行のタイムアウト処理が、次の実行をキャンセルすることはありません。
独立したクエリを並列実行するには、同じConnectionを複数ワーカーで共有せず、接続プールから
ワーカーごとに論理Connectionを借り出します。実行中のフェッチを終了する場合は、別スレッドから
`close()`、`cancel()`、`Connection.abort()`を呼び出せます。
---
title: "11.5.3 トランザクションと接続プール"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/transaction-pooling/
language: ja
kind: page
---
# 11.5.3 トランザクションと接続プール
Machbase JDBCはStandard EditionのTRANSACTIONテーブルで標準JDBCのローカルトランザクションを
サポートします。Cluster EditionにはTRANSACTIONテーブルがないため、このページのトランザクション
機能は適用しません。
## TRANSACTIONテーブルの作成
```sql
CREATE TRANSACTION TABLE sensor_tx
(
id INTEGER PRIMARY KEY,
parent_id INTEGER,
name VARCHAR(64),
value DECIMAL(20, 4),
created_at DATETIME,
payload BINARY
);
```
## コミットとロールバック
`setAutoCommit(false)`、`commit()`、`rollback()`を使用します。
アプリケーションからSQLの`BEGIN`を直接送る必要はありません。
```java
import java.sql.PreparedStatement;
import java.sql.SQLException;
connection.setAutoCommit(false);
try (PreparedStatement statement = connection.prepareStatement(
"INSERT INTO sensor_tx (id, value) VALUES (?, ?)")) {
statement.setInt(1, 1);
statement.setBigDecimal(2, new BigDecimal("10.5000"));
statement.executeUpdate();
connection.commit();
} catch (SQLException exception) {
try {
connection.rollback();
} catch (SQLException rollbackException) {
exception.addSuppressed(rollbackException);
}
throw exception;
}
```
`setAutoCommit(false)`は直ちに`BEGIN`を送りません。手動モードで最初のStatementを実行する際に
トランザクションを開始します。コミットまたはロールバック後もauto-commitは`false`のままで、
次のStatementが新しいトランザクションを開始します。
- `setAutoCommit(true)`へ切り替える際、有効なトランザクションがあれば先にコミットします。
- auto-commitが`true`のときに`commit()`または`rollback()`を呼ぶと、SQLState `25000`になります。
- Connectionを閉じる際、未完了のトランザクションはロールバックされます。
- コミットとロールバックは開いたResultSetを閉じますが、Statementは再利用できます。
## 分離レベルとカーソル
サポートする分離レベルは`Connection.TRANSACTION_SERIALIZABLE`です。他の分離レベルを要求すると
`SQLFeatureNotSupportedException`になります。
サポートするカーソル保持設定は`ResultSet.CLOSE_CURSORS_AT_COMMIT`です。
コミット前に必要なResultSetを読み取るか、コミット後にクエリを再実行します。
## テーブルタイプ別の動作
| 操作 | 手動トランザクションでの動作 |
|------|--------------------------|
| TRANSACTIONテーブルのDML/SELECT | トランザクションに参加します。 |
| LOG/TAGテーブルのSELECT | 実行できます。 |
| TRANSACTION変更前の最初のLOG DML | 互換経路でauto-commitとして再実行される場合があります。 |
| 独立したTAG DML | トランザクションに参加し、ロールバックできます。 |
| TRANSACTION変更後のLOG/TAG DMLまたはDDL | エラーになります。 |
互換経路でauto-commit再実行されたLOG DMLは、後続のロールバック対象ではありません。
ロールバックが必要なデータにはTRANSACTIONテーブルを使用します。複数のTRANSACTIONテーブルの
通常のコミットとロールバックはサポートしますが、バックエンドのコミット中に障害が起きた場合の
全体の原子性は保証しません。重要なアトミック操作は1つのTRANSACTIONテーブルの範囲で設計します。
## DataSource
`MachDataSource`は、アプリケーションサーバーやフレームワークに接続プロパティを注入する際に使用します。
```java
import com.machbase.jdbc.MachDataSource;
import java.sql.Connection;
MachDataSource dataSource = new MachDataSource();
dataSource.setUrl("jdbc:machbase://127.0.0.1:5656/machbasedb");
dataSource.setUser("SYS");
dataSource.setPassword(System.getenv("MACHBASE_PASSWORD"));
dataSource.setLoginTimeout(10);
try (Connection connection = dataSource.getConnection()) {
// SQLを実行します。
}
```
DataSourceはURL、ユーザー、password、ログインタイムアウト、ログwriter、JDBCの`Wrapper`仕様を
サポートします。
## ConnectionPoolDataSource
`MachConnectionPoolDataSource`は物理接続を直接公開せず、論理Connectionを返します。
```java
import com.machbase.jdbc.MachConnectionPoolDataSource;
import java.sql.Connection;
import javax.sql.PooledConnection;
MachConnectionPoolDataSource source =
new MachConnectionPoolDataSource();
source.setUrl("jdbc:machbase://127.0.0.1:5656/machbasedb");
source.setUser("SYS");
source.setPassword(System.getenv("MACHBASE_PASSWORD"));
PooledConnection pooled = source.getPooledConnection();
try {
try (Connection logical = pooled.getConnection()) {
// 論理接続を使用します。
}
} finally {
pooled.close();
}
```
1つのPooledConnectionでは論理ハンドルを1つだけ有効にします。論理Connectionを閉じると、
次の状態を初期化してから`connectionClosed`イベントが1回発生します。
- 未完了トランザクションのロールバック
- auto-commitの復元
- URLで決まる初期カタログの復元
- ネットワークタイムアウトの復元
クローズを開始した論理ハンドルの呼び出しが終わる前に、次の貸し出しは行いません。
閉じたConnection、Statement、DatabaseMetaDataは次に接続を借りたリクエストで再利用できず、
SQLState `08003`になります。Statement poolingはサポートしません。
SQLStateクラス`08`の致命的な接続エラーでは物理接続を破棄し、`connectionErrorOccurred`を発生させます。
重複キーなどクラス`23`のエラーは接続破損ではないため、接続エラーイベントを発生させません。
## HikariCP
```java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:machbase://127.0.0.1:5656/machbasedb");
config.setUsername("SYS");
config.setPassword(System.getenv("MACHBASE_PASSWORD"));
config.setMaximumPoolSize(10);
config.setMinimumIdle(2);
config.setConnectionTimeout(30_000);
config.setIdleTimeout(600_000);
config.setMaxLifetime(1_800_000);
config.addDataSourceProperty("TIMEZONE", "+0900");
try (HikariDataSource dataSource = new HikariDataSource(config);
Connection connection = dataSource.getConnection()) {
// SQLを実行します。
}
```
論理Connectionはtry-with-resourcesで速やかに返却し、返却済みのハンドルを保持しません。
## ネットワークタイムアウト
`setNetworkTimeout(executor, milliseconds)`はソケット読み取りタイムアウトをミリ秒単位で設定し、
`0`は無制限です。負の値、null executor、またはタスクを拒否するexecutorは`SQLException`になります。
実際にネットワークタイムアウトが発生するとSQLStateクラス`08`の例外が発生し、物理接続は無効になります。
その接続で作成したStatementとResultSetは再利用せず、新しい接続を借り出します。
有効なトランザクションのI/O失敗は自動再実行しません。
---
title: "11.5.4 DatabaseMetaData"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/database-metadata/
language: ja
kind: page
---
# 11.5.4 DatabaseMetaData
`Connection.getMetaData()`はドライバー、サーバー、スキーマオブジェクト、JDBC機能の情報を返します。
結果列はJDBC標準の名前と順序を使用するため、数値の位置より列名で読み取ることを推奨します。
```java
import java.sql.DatabaseMetaData;
DatabaseMetaData metadata = connection.getMetaData();
System.out.println(metadata.getDriverName());
System.out.println(metadata.getDriverVersion());
System.out.println(metadata.getDatabaseProductName());
System.out.println(metadata.getDatabaseProductVersion());
```
## テーブルとVIEW
```java
try (ResultSet tables = metadata.getTables(
null, null, "%", new String[] {"TABLE", "VIEW"})) {
while (tables.next()) {
System.out.printf("%s %s%n",
tables.getString("TABLE_NAME"),
tables.getString("TABLE_TYPE"));
}
}
```
`getTables()`はTABLEとVIEWを区別します。Machbaseの詳細なテーブルタイプは`REMARKS`で確認します。
アプリケーションは特定の位置番号に依存せず、標準列名を使用します。
## 列
```java
try (ResultSet columns = metadata.getColumns(
null, null, "SENSOR_TX", "%")) {
while (columns.next()) {
System.out.printf(
"%s %s size=%d nullable=%s%n",
columns.getString("COLUMN_NAME"),
columns.getString("TYPE_NAME"),
columns.getInt("COLUMN_SIZE"),
columns.getString("IS_NULLABLE"));
}
}
```
`NULLABLE`は数値定数、`IS_NULLABLE`は`YES`、`NO`、または空文字列で返ります。
LOOKUPとVOLATILEテーブルのPRIMARY KEYは、明示的なNOT NULL句がなくても`columnNoNulls`と
`NO`で返ります。
VARCHAR、DATETIME、BINARY、BLOB、CLOBなど数値属性が適用されない列の`DECIMAL_DIGITS`と
`NUM_PREC_RADIX`はSQL NULLです。`getInt()`の0だけを見ず、`getObject()`または`wasNull()`で
NULLかどうかを確認します。
## PRIMARY KEYとインデックス
```java
try (ResultSet keys = metadata.getPrimaryKeys(
null, null, "SENSOR_TX")) {
while (keys.next()) {
System.out.printf("%s position=%d%n",
keys.getString("COLUMN_NAME"),
keys.getShort("KEY_SEQ"));
}
}
try (ResultSet indexes = metadata.getIndexInfo(
null, null, "SENSOR_TX", false, false)) {
while (indexes.next()) {
System.out.printf("%s %s%n",
indexes.getString("INDEX_NAME"),
indexes.getString("COLUMN_NAME"));
}
}
```
PRIMARY KEYかどうかを`ResultSetMetaData.isNullable()`の値から推測しません。
`getPrimaryKeys()`と`getIndexInfo()`を使用します。
SELECT結果の直接の列がPKかどうかは、Machbase JDBC拡張の
`MachResultSetMetaData.isPrimaryKey(column)`で確認できます。
```java
import com.machbase.jdbc.MachResultSetMetaData;
try (ResultSet result = statement.executeQuery(
"SELECT ID, ID + 1 AS ID_EXPR FROM SENSOR_TX")) {
MachResultSetMetaData resultMetadata =
(MachResultSetMetaData) result.getMetaData();
System.out.println(resultMetadata.isPrimaryKey(1)); // trueまたはfalse
System.out.println(resultMetadata.isPrimaryKey(2)); // 式: false
}
```
`getPrimaryKeys()`はテーブルカタログのPKを検索し、`isPrimaryKey()`は現在のSELECT結果の
列メタデータを取得します。旧バージョンのサーバーまたはSDKに接続した場合、結果列のPKフラグが
`false`として返る場合があります。
## スキーマと型情報
次のメソッドはJDBC標準形式のResultSetを返します。
- `getSchemas()`、`getCatalogs()`、`getTableTypes()`
- `getTypeInfo()`
- `getTables()`、`getColumns()`
- `getPrimaryKeys()`、`getIndexInfo()`
非サポートの任意メタデータ検索は、nullや非標準のResultSetではなく、標準列を持つ空のResultSetを
返す場合があります。機能を使用する前に機能メソッドを確認します。
```java
if (metadata.supportsSavepoints()) {
// 対応環境でのみセーブポイントを使用します。
}
```
## カタログ
`Connection.getCatalog()`と`setCatalog()`は、ドライバーが公開する現在のカタログ値を管理します。
メタデータメソッドのカタログ引数は、この値と一致する要求をフィルターするために使用します。
```java
String initialCatalog = connection.getCatalog();
connection.setCatalog(initialCatalog);
```
接続プールに論理Connectionを返却すると、カタログはURLで決まる初期値に復元されます。
前の接続貸し出し期間で取得したDatabaseMetaDataオブジェクトは、次の貸し出し期間で再利用しません。
## サポート範囲の確認
Machbase JDBCは実際のサポート範囲を機能情報に反映します。たとえばトランザクションの分離レベル、
ResultSetの種類、セーブポイント、生成キー、複数結果の同時オープンのサポートを次のように確認します。
```java
System.out.println(metadata.supportsTransactions());
System.out.println(metadata.supportsTransactionIsolationLevel(
Connection.TRANSACTION_SERIALIZABLE));
System.out.println(metadata.supportsResultSetType(
ResultSet.TYPE_FORWARD_ONLY));
System.out.println(metadata.supportsSavepoints());
System.out.println(metadata.supportsGetGeneratedKeys());
System.out.println(metadata.supportsMultipleOpenResults());
```
`Driver.jdbcCompliant()`が`false`であることと、個々のJDBC APIのサポート状況は別です。
アプリケーションは必要な機能を直接確認します。
Standard EditionでROWID対応サーバーに接続すると、`supportsGetGeneratedKeys()`は`true`、
`getRowIdLifetime()`は`ROWID_VALID_OTHER`を返します。非対応サーバーまたはCluster Editionでは、
それぞれ`false`と`ROWID_UNSUPPORTED`を返します。使用例は
[ROWIDとINSERT結果ID](/ja/dbms/reference/sql/rowid/)を参照してください。
---
title: "11.5.5 Append API"
url: https://docs.machbase.com/ja/dbms/development-tools-integration/jdbc/append-api/
language: ja
kind: page
---
# 11.5.5 Append API
Machbase Append APIは複数行を連続して入力する大量入力APIです。JDBCでは`MachStatement`の
拡張メソッドを使用します。このページはLOG入力の例を中心に説明します。他のテーブルタイプの
サポート範囲は[SDKサポート表](../../sdk-support-scope/#append-table-type-matrix)も確認してください。
## API
| メソッド | 説明 |
|--------|------|
| `executeAppendOpen(tableName, errorCheckCount)` | Appendセッションを開始し、列メタデータを返します。 |
| `executeAppendOpen(tableName, inputColumns, errorCheckCount)` | Machbase DBMS 8.7.0で選択列またはARRAY要素を対象にAppendセッションを開始します。 |
| `executeAppendData(metadata, data)` | 1行を送信します。 |
| `executeAppendDataByTime(metadata, time, data)` | ナノ秒の時刻を指定して1行を送信します。 |
| `executeAppendFlush()` | 保留中の応答を同期します。 |
| `executeAppendClose()` | Appendセッションを終了します。 |
| `executeSetAppendErrorCallback(callback)` | 行エラーのコールバックを登録します。 |
| `getAppendSuccessCount()` | 成功した行数を返します。 |
| `getAppendFailureCount()` | 失敗した行数を返します。 |
公開メソッド`executeAppendData()`は成功すると`1`を返し、無効な内部結果には`SQLException`を
スローします。最終的な成功・失敗件数とコールバックも確認します。
## 入力例
```sql
CREATE LOG TABLE sensor_data (
time DATETIME,
name VARCHAR(40),
value DOUBLE
);
```
```java
import com.machbase.jdbc.MachStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
try (MachStatement statement =
(MachStatement) connection.createStatement()) {
ResultSet appendResult =
statement.executeAppendOpen("sensor_data", 100);
ResultSetMetaData metadata = appendResult.getMetaData();
statement.executeSetAppendErrorCallback(
(errorNumber, errorMessage, rowMessage) ->
System.err.printf(
"Append error [%05d]: %s%n%s%n",
errorNumber, errorMessage, rowMessage));
long baseTime = System.currentTimeMillis() * 1_000_000L;
for (int index = 0; index < 10_000; index++) {
ArrayList