2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Select AIのSQL生成精度、プロンプトではなく「スキーマ側」に握る。COMMENT・ANNOTATIONS・Domainの使い分けを整理してみた

2
Posted at

初めに

NL2SQL(自然言語でSQLを作る仕組み)を作っていると、ある壁に必ず当たります。

表名・列名・データ型だけでは、業務の意味は伝わらない。

例えば CUST_MST と ORD_TXN という2つの表があったとします。物理スキーマだけを見ると、STAT_CD が何のステータスなのか、AREA_CD = '01' が「関東」のことだなんて、LLMにはわかりません。

Oracle AI Database 26ai の Select AI では、こうした「業務の意味」をデータベース側に持たせる手段として、次の3つ(+1つ)が用意されています。

  • COMMENT
  • ANNOTATIONS
  • Domain(Data Use Case Domain)
  • (ついでに)View / Materialized View

一見すると「表や列に説明を付ける」ことで同じに見えますが、実は役割がまったく違います。

この記事では、[shirok さんの検証記事]

(Oracle AI Database 26ai / Select AI で実機検証した2部構成の第2部)の内容をベースに、

  1. 3つそれぞれの役割と違い
  2. どんなシーンで何に使うとよいのか
  3. それぞれがSQL生成のどの精度を底上げするのか

を整理します。

Select AI が Metadata から SQL を生成する仕組みそのものについては、同じく shirok さんの第1部が非常に分かりやすいので、そちらを先に読むのがおすすめです。

結論

先に結論です。

COMMENT・ANNOTATIONS・Domain は「どれか1つ」の代替関係ではなく、役割が異なる3つのレイヤとして組み合わせるものです。

人向けの説明          ->  COMMENT
AI/アプリ向けの意味   ->  ANNOTATIONS
業務値の再利用・強制   ->  Domain
問い合わせ構造の単純化 ->  View / MV

精度への影響を一言でまとめるとこうです。

機能 一言で言うと 精度を上げる対象
COMMENT 人向けの一言説明 コード値→業務意味の変換(A=有効、01=関東 等)
ANNOTATIONS 用途別に分けた構造化メタデータ 用語マッチング・JOIN判断・単位・粒度
Domain 業務上同じ値の「再利用可能なデータ型」 複数テーブル間の一貫性・制約の強制(単発精度より運用精度)
View / MV AI向けの問い合わせ構造 SQLの複雑さ自体を削減(生成ミスの素を減らす)

shirok さんの検証では、以下のような結果が出ています(検証環境: Oracle AI Database 26ai EE 23.26.3.2.0、OpenAI / gpt-5.6-luna、SQLcl)。

パターン 「有効顧客は何人?」 「確定済み売上合計は?」 「関東の有効顧客の確定済み売上(顧客別)」
何もしない(基本Metadataのみ) ×(STAT_CD='1' と誤推測して 0 人) ○ 37,000円(たまたま当たり) × 未定義のバインド変数が出て実行不能
+ COMMENT ○ 3人 ○ 37,000円 ○
+ 直接Annotations ○ 3人 ○ 37,000円 ○
+ Domain + 直接Annotations ○ 3人 ○ 37,000円 ○
AI向けView(構造変更) - - ○(生成SQLは WHERE AREA_CD='01' のみ)

つまり、COMMENT も Annotations も「業務用語とコード値の解釈」を直撃し、Domain は「一貫性と管理性」、View は「問題の単純化」を担う、という分担になります。

1. Select AI が何を見ているのか(前提の整理)

Select AI が LLM に送るものは、基本 Metadata(表名・列名・データ型)に、プロファイルの設定次第で COMMENT / Annotations / 制約情報が加わります。

"comments": true      // 表・列の COMMENT をプロンプトに追加
"annotations": true   // 表・列の Annotations をプロンプトに追加
"constraints": true   // 主キー・外部キーなどの参照整合性情報を追加

この3つは デフォルトでは OFF なので、付与してもプロファイルで ON にしないと LLM には届きません。地味な落とし穴です。

確認の仕方も押さえておきます。

-- LLM に実際に渡る内容を確認
SELECT AI SHOWPROMPT <質問>;

-- 生成された SQL を確認
SELECT AI SHOWSQL <質問>;

SHOWPROMPT に Annotation 名と値が含まれていれば「LLM に届いた」と判定できます。ただし DOMAIN_NAME は表示されないので、「これが Domain 由来か直接付与か」の切り分けは USER_ANNOTATIONS_USAGE で行います(両者を突き合わせて検証するのが shirok さんの記事のやり方で、ここが丁寧で良い)。

2. COMMENT:人向けの「一行説明」

2.1 仕組み

COMMENT は昔ながらの「表・列に1文字列の説明文を付ける」機能です。

COMMENT ON TABLE cust_mst IS '顧客基本情報。1行=1顧客。';

COMMENT ON COLUMN cust_mst.stat_cd
  IS '顧客ステータス。A=有効, I=休眠。';

COMMENT ON COLUMN ord_txn.amt
  IS '受注1件の売上金額(日本円)。確定済みの判定は ORD_TXN.STAT_CD で行う。';
  • 表・列に 1件だけ 付与できる自由な文字列
  • Oracle Database 自身が内容を解釈・強制はしない(メモに過ぎない)
  • IDE、設計書生成ツール、データカタログなど「人が見る側」の標準的な説明欄
  • View 全体に付ける場合は COMMENT ON TABLE view_name IS '...'(COMMENT ON VIEW は存在しない)
  • Domain への COMMENT は存在しない(Domain 自体の説明は Annotations)

確認は USER_TAB_COMMENTS / USER_COL_COMMENTS。削除は空文字列を設定します(COMMENT ON COLUMN ... IS '';)。

2.2 どの精度が上がるか

検証で効いたのは 「コード値の読み替え」 です。

COMMENT なしの状態で「有効顧客は何人ですか?」と聞くと、LLM は STAT_CD = '1' と勝手に推測して 0人 という誤答になります。一方、「A means active」と COMMENT に書いておくだけで STAT_CD = 'A' で正しく 3人を返します。

精度観点: 「値の意味」を伝えることによる WHERE 条件の正確化。

2.3 向いているシーン・限界

  • 向いている: 表・列の用途を「人間が5秒で理解できる」レベルで説明したいとき。既存のドキュメント生成・データカタログとも相性が良い
  • 限界: 1列に1文書しか書けない。別名・単位・JOIN先・コード値一覧を用途別に分けたくても、全部1つの文章に詰め込むしかない

3. ANNOTATIONS:AI向けの「構造化メタデータ」

3.1 仕組み

Annotations は 名前/値のペアを複数個 付ける仕組みです。Annotation 名は最初に使った時点で自動登録されるので、事前に Domain へ辞書登録する必要はありません。表・列だけでなく View・View列にも直接付与可能です。

ALTER TABLE cust_mst
  MODIFY stat_cd ANNOTATIONS (
    "DESCRIPTION" 'Customer status code.',
    "ALIASES"     'customer status, active customer, 顧客状態, 有効顧客',
    "VALUES"      'A = active (有効); I = inactive (休眠).'
  );

ALTER TABLE ord_txn
  MODIFY cust_id ANNOTATIONS (
    "DESCRIPTION" 'Customer identifier.',
    "JOIN COLUMN" 'Join with CUST_MST.CUST_ID.'
  );

Oracle の AI Enrichment ガイドで推奨されているラベルは、次の5つです(予約語ではなく推奨の命名規則)。

Annotation 用途
DESCRIPTION 表・列の業務的な意味、1行の粒度
ALIASES 別名・同義語・ユーザーが実際に使う呼び方
UNITS 通貨・距離・重量などの単位
JOIN COLUMN 推奨される JOIN 先と、その関係の意味
VALUES コード値、代表値、値の意味

実運用で踏むポイント:

  • 名前: 最大1,024文字 / 値: 最大4,000文字
  • 同名 Annotation を重複 ADD すると ORA-11552。更新は REPLACE、冪等にしたいなら ADD IF NOT EXISTS
  • 値の意味はデータベースが強制しない(制約ではない)
  • 自由度が高い分、DESCRIPTION / DESC / BUSINESS_DESC とラベル名の表記揺れが起きやすい。命名・言語・値の形式をチームで先に標準化する

3.2 どの精度が上がるか

COMMENT と比べると「構造」の差が効いてきます。

ラベル 精度を上げるポイント
ALIASES 「顧客番号」「取引先ID」「売上」といったユーザーの言い回しが物理列名と一致しない問題を解決。テーブル・列の選択精度が上がる
VALUES STAT_CD='A' が「有効」だと確実に分かる。WHERE 条件の値変換精度が上がる
JOIN COLUMN どの列同士を JOIN すべきか明示。物理 FK 情報をプロンプトに入れない(constraints: false)状態で JOIN を正しく引ける
UNITS 金額の単位(日本円等)の取り違えを防ぐ
DESCRIPTION 「1行=1受注」のような粒度情報を伝え、集計方法の誤りを防ぐ

shirok さんの検証では、直接 Annotations のみのパターンでも3問すべて正解でした。

3.3 向いているシーン・限界

  • 向いている: 別名だらけの業務システム、コード値が多い列、AI だけが使う説明を既存 COMMENT から分離したいとき
  • 限界1: 再利用できない。同じ意味の別名を10個のテーブルの同じ列に付けたいと、10回分書き直す(更新漏れが起きる)
  • 限界2: 自由度が高すぎてラベルが揺れる。標準化しないとかえって LLM を混乱させる

4. Domain:業務上の「データ型」として再利用する

4.1 仕組み

Domain は「業務上の値」を表す スキーマ・オブジェクトです。「タグを付ける機能」ではなく、型・制約・デフォルト・表示・並び順・Annotations をまとめた再利用可能な定義だと思っています。

CREATE DOMAIN customer_status_d AS CHAR(1)
  CONSTRAINT customer_status_d_ck CHECK (VALUE IN ('A', 'I'))
  ANNOTATIONS (
    "DESCRIPTION" 'Customer status code.',
    "ALIASES"     'customer status, active customer, 顧客状態, 有効顧客',
    "VALUES"      'A = active (有効); I = inactive (休眠).'
  );

CREATE DOMAIN sales_area_d AS CHAR(2)
  CONSTRAINT sales_area_d_ck CHECK (VALUE IN ('01', '02'))
  ANNOTATIONS (
    "DESCRIPTION" 'Sales area code assigned to a customer.',
    "ALIASES"     'sales area, region, 営業地域, 地域',
    "VALUES"      '01 = Kanto (関東); 02 = Kansai (関西).'
  );

既存の列に適用すると、Domain に付けた Annotations が その列へ自動継承されます。

ALTER TABLE cust_mst MODIFY (stat_cd) ADD DOMAIN customer_status_d;
ALTER TABLE ord_txn  MODIFY (amt)     ADD DOMAIN sales_amount_d;

継承を確認するには USER_ANNOTATIONS_USAGE を見ます。

SELECT object_name, object_type, column_name,
       domain_owner, domain_name,   -- NULL=直接付与 / 値あり=Domain由来
       annotation_name, annotation_value
FROM   user_annotations_usage
ORDER  BY object_name, column_name, annotation_name;

4.2 どの精度が上がるか

正直に書くと、単発の SQL 生成精度が Annotations のみより上がる、とは限りません(shirok さんの検証でも、直接 Annotations と Domain+直接 Annotations で結果は同点でした)。

Domain が効くのは別の次元です。

  • 一貫性: 「顧客ID」の意味・別名を customer_id_d に1つだけ定義し、CUST_MST.CUST_ID と ORD_TXN.CUST_ID 両方に適用。定義箇所が1つになる
  • 強制力: CHECK (VALUE IN ('A','I')) は Annotations と違いデータベースが強制する。LLM に「A か I」と言わなくても、不正値は入らない
  • 管理性: 複数テーブルで共通する「顧客ID」「通貨」「メール形式」の定義を1箇所で変更管理できる

精度観点: 単発の正解率より、「定義が複数箇所に分散してズレる事故」を構造的に減らす運用精度。

4.3 使わないほうがよい場面・注意点

  • Domain はタグ集ではない。1列に付けられる Domain は 1つだけ。Customer / PII / Gold のように複数タグを振りたい場合は Annotations を使う
  • 適用前に互換性を確認。型・長さ・精度・スケール(STRICT なら完全一致)・デフォルト値・照合順序が噛み合わないと関連付けできない。「Annotations を付けたい」だけで Domain を作るのではなく、「Domain の制約やデフォルト値ごとその列に適用してよいか」で判断する
  • View 列に ADD DOMAIN する DDL は存在しない(単純投影列はベース表の Domain 情報を保持する)
  • Domain 列レベルの Annotation は ALTER DOMAIN では変更できない(Domain の再作成が必要)。オブジェクトレベルと列レベルで同名 Annotation を付けると、参照先列に同名 Annotation が重複表示される
  • Domain 由来の制約・表示式・並び順が Select AI のプロンプトに自動追加されるかは、公式資料には明記されていない。実際に SHOWPROMPT で確認するのが安全

5. 補足: View で「問題そのもの」を単純化する

shirok さんの検証で最も印象的だったのがこの部分です。

「関東の有効顧客について、確定済み売上金額を顧客別に表示してください」に対する生成 SQL は、ベース表を直接使うパターンだとこんな感じです。

SELECT c.CUST_NM, SUM(o.AMT) AS CONFIRMED_SALES_AMT
FROM   CUST_MST c
JOIN   ORD_TXN o ON o.CUST_ID = c.CUST_ID
WHERE  c.AREA_CD = '01'
AND    c.STAT_CD = 'A'
AND    o.STAT_CD = 'C'
GROUP BY c.CUST_ID, c.CUST_NM;

JOIN、2つのステータス条件、SUM、GROUP BY を全部 LLM に考えさせられています。これを「AI 問い合わせ用 View」で吸収すると、

-- View 側で JOIN・有効顧客・確定済みの条件・集計を実装済み
SELECT c.CUST_ID, c.CUST_NM, c.CONFIRMED_SALES_AMT
FROM   CUST_CONFIRMED_SALES_V c
WHERE  c.AREA_CD = '01';

と、WHERE 条件1つだけの SQL になります。業務ロジックを View の SQL に移したことで、LLM が間違える箇所自体が減ったわけです。View 列にも Annotations(DESCRIPTION / ALIASES / UNITS)を直接付けられるので、算出列の意味も伝えられます。

精度観点: メタデータで「伝える」のではなく、SQL の複雑さ自体を減らす。これがいちばん確実。

注意点として、Domain を持つ列を単純投影した View 列は Domain 由来の Annotation を保持する一方、View 列に同名 Annotation を直接付けると重複します(検証では 17件 → 重複5件を削除して12件に整理)。Domain を保持する単純投影列には同じ Annotation を重ねず、View 固有の意味(粒度・算出列・単位)だけ直接付与するのが整理しやすそうです。

6. 実運用での設計方針(まとめ)

伝えたいこと 置く場所 例
人向けの短い基本説明 COMMENT 表の用途、列の概要
表・列固有の業務的な意味 直接 Annotations 粒度、別名、コード値
AI へ伝える推奨 JOIN・関係 直接 Annotations(JOIN COLUMN) 「この列は ORD_TXN.CUST_ID と JOIN する」
複数テーブルで共通する安定した業務値 Domain 顧客ID、通貨、メールアドレス
厳密に守るべき値のルール Domain の CHECK / PK / FK ステータス値の制限、金額の非負
JOIN・計算・集計・公開粒度 View / MV 顧客別売上、月次売上
View 固有の意味 View 列への直接 Annotations 1行の粒度、算出列の意味、単位

原則は2つです。

  1. 共通で安定した意味とルール → Domain。オブジェクト固有の文脈 → 直接 Annotations。人の説明 → COMMENT
  2. 「説明」と「強制すべきルール」を分ける。Annotation に「売上は確定済み受注の税引前金額」と書いても、DB はそれを強制しません。常に同じ結果でなければならない計算は View の SQL や制約で実装し、Annotation は「その実装の意味を AI に伝える」ために使う

運用面の注意

  • COMMENT と DESCRIPTION の二重管理: 既存 COMMENT を消して Annotations 一本にする必要はない(IDE やデータカタログがまだ COMMENT を参照している可能性)。ただし「どちらを正本とするか・更新ルール」を決め、矛盾した説明を LLM に渡さないこと。Select AI で両方を ON にした場合の優先順位は、shirok さんの記事時点で公式ドキュメントに明記されていません
  • ラベル名を標準化する: DESCRIPTION / ALIASES / UNITS / JOIN COLUMN / VALUES を基本セットにし、独自ラベルを追加するなら名前・適用対象・値の書式・記述言語・更新責任者をチームで決める
  • 日本語の業務用語: Oracle は Annotations を明確な英語で書くことを推奨。日本語で質問が来る環境では、ALIASES / VALUES に日本語の呼び方を併記するのが実用的('顧客状態, 有効顧客' のような形)。英語のみ / 日本語のみ / 併記、どれが精度高いかはモデル依存なので要検証
  • 秘密情報を書き込まない: COMMENT / Annotations はデータディクショナリから読めるし、プロファイル設定次第で LLM へ渡ります
  • DDL として変更管理する: COMMENT・Annotations・Domain・View はすべて DDL。Git で管理し、テーブル定義と一緒にレビューできる形に

最後に

今回の整理で、腑に落ちたポイントを3つ。

  1. 「精度を上げる」の正体は、業務用語とコード値の解釈。表名・列名・型だけでは推測できない STAT_CD='A' のような意味を、COMMENT か Annotations で LLM に渡せるか、が最初の分岐点
  2. Domain の価値は再利用と強制。1問の正解率を上げる機能ではなく、複数テーブルに散らばる「顧客ID」の定義を1箇所に集め、制約まで強制する仕組み
  3. 一番効くのは場合によっては View。メタデータを整備するより先に、「AI に見せる構造」をどう設計するかが効く

「AI Ready Data」と言うと Vector 化や RAG ばかりが語られがちですが、データが何を意味し、どの値を使い、どう結合し、どの粒度で問い合わせるのかを Database 側に整えることも、ちゃんとした AI Ready Data の一部です。

プロンプト側をいじるより、スキーマ側に意味を持たせる。これが Select AI を使う上での一番の視点の転換でした。

参考

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?