エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

AIに正しく分析してもらうためのテーブル設計戦略

この記事はエムスリー Advent Calendar 2025 16日目の記事です。

こんにちは、AI・機械学習チームの須藤です。

現在は、BigQuery上のデータを自然言語で分析できる社内向けプロダクトを開発しています。本記事では、AIに正しくデータを分析してもらうために工夫したテーブル設計戦略について紹介します。

データ分析の民主化

昨今、AIエージェントの活用が進んでいます。これまでのAIはチャット相手としての側面が強かったですが、MCP(Model Context Protocol)*1などの登場により、AIが外部ツール(データベースやAPI等)を直接操作できるエージェントへと進化してきました。

MCPサーバーは既に様々なものが提供されていますが、BigQueryを利用するためのMCPサーバーも既に提供されています。*2 これらの仕組みを活用すれば、BigQuery上の膨大なデータを、エンジニアの手を借りることなく、ビジネスサイドのメンバーが直接分析できるようなインタフェースを提供できます。

たとえば、「30代のユーザーの昨日の売上推移はどうなってる?」と日本語で聞けば、数分後にはAIがSQLを書いて実行し、分析結果を提供してくれる。……といったことが実現可能です。

まさに「データ分析の民主化」と言えると思います。

しかし、AIに正しくデータを分析してもらうためには、「どのような形式のデータを分析対象とするか」が非常に重要になってきます。

AIがデータ分析する際に起こり得る問題

正規化された多数のテーブルを適切にJOINし、正しい粒度で集計することは、人間にとっても認知負荷の高いタスクです。

AIの性能が良くなっているとはいえ、複雑なスキーマ構造を扱う際に、結合条件の誤選択等のミスが発生するリスクはゼロではありません。

AIにデータ分析を任せる際、こうしたテーブル結合のミスが発生し、それが誤集計につながってしまうことは、容易に想像できるかと思います。

JOINと行増殖のリスク

データベースの設計では、データの整合性を保つために正規化を行い、複数のテーブルに分散して保存するのが一般的かと思います。 人間が分析する場合、これらを適切にJOINしてデータを抽出しますが、このJOINが分析における難しいポイントの1つです。

具体的には、次のようなECサイトのテーブル構成を考えてみましょう(本記事ではBigQueryを想定しています)。

-- ユーザー情報
CREATE TABLE users (
  user_id STRING,
  name STRING,
  age INT64
);

-- 注文情報
CREATE TABLE orders (
  order_id STRING,
  user_id STRING,
  order_date DATE
);

-- 注文明細
CREATE TABLE order_items (
  item_id STRING,
  order_id STRING,
  product_name STRING,
  quantity INT64,
  price INT64
);

この状態で、例えば「先月購入があった30代のユーザー数」を知りたいとします。

本来であれば、usersテーブルと、ordersテーブルを結合すれば十分で、明細情報のorder_itemsテーブルは不要です。 しかし、AIが注文に関する詳しい情報も必要だと判断してしまい、次のようなSQLを生成してしまう可能性は0ではありません。

SELECT
  COUNT(u.user_id) AS user_count
FROM
  users u
JOIN
  orders o ON u.user_id = o.user_id
JOIN
  order_items oi ON o.order_id = oi.order_id 
WHERE
  u.age BETWEEN 30 AND 39
  AND o.order_date BETWEEN '2025-11-01' AND '2025-11-30'

想定しているテーブル構造では、1つの注文に複数の商品が紐づくのが一般的です。その状態でorder_itemsを結合してしまうと、商品の数だけ行が増えてしまいます。

もしそのままユーザー数をカウントしようとすると、1人のユーザーが1回の注文で3種類の商品を購入した場合に、3人としてカウントされてしまいます。 結果として、ユーザー数が実際の3倍になってしまうなどの誤った数値に基づいて意思決定を行えば、ビジネスに重大な悪影響を及ぼす可能性があります。

プロンプトで「気をつけて」と指示することである程度防ぐことは可能ですが、AIに高いパフォーマンスを発揮してもらうためには、より構造的なサポートが必要です。

解決策:AIのための「非正規化」

この問題の解決策の1つとして考えられるのが、プロンプトエンジニアリングですべてを解決しようとするのではなく、「AIが得意なシンプルなタスクに集中できる環境」を用意するアプローチです。

分析専用のOne Big Tableを用意する

具体的には、AIに正規化されたテーブル群を見せるのではなく、あらかじめ必要な結合を全て済ませた「分析専用の巨大なテーブル(One Big Table)」*3を1つだけ用意する、という方針です。

いわゆる非正規化です。 ECサイトの例で言うと、このテーブルには、ユーザー属性、注文日時、商品カテゴリなど、分析に必要なあらゆる情報が含まれることになります。

JOINを物理的に排除する

この設計の最大のメリットは、AIが生成するSQLからJOIN句が消滅することです。

分析に必要な情報はすべて1行にまとまっているため、AIは集計項目の選択と、条件による絞り込みに集中できます。

実際のテーブル定義のイメージは次のようになります。

CREATE TABLE analysis_mart (
  -- ユーザー情報
  user_id STRING,
  user_age INT64,
  user_name STRING,

  -- 注文情報
  order_id STRING,
  order_date DATE,

  -- 注文明細情報
  items ARRAY<STRUCT<
    item_id STRING,
    product_name STRING,
    product_category STRING,
    quantity INT64,
    price INT64
  >>
);
PARTITION BY order_date;

このように結合済みのテーブルを用意して、AIにはこのテーブルだけを参照させることで、複雑なJOIN操作によるミスを根本から防ぐことが期待できます。

実際に、先ほどの「先月購入があった30代のユーザー数」という質問に対して、AIが生成するSQLは次のようになるかと思います。

SELECT
  COUNT(DISTINCT user_id) AS user_count
FROM
  analysis_mart
WHERE
  user_age BETWEEN 30 AND 39
  AND order_date BETWEEN '2025-11-01' AND '2025-11-30'

このように、JOIN句は出現せず、SELECTとWHEREだけのシンプルなSQLになります。これにより、AIが間違える余地を最小限に抑えることが期待できます。

注意点

ここまで「AIにデータを分析してもらう」という文脈で非正規化を提案してきましたが、導入にあたっては、主に次の2点に注意する必要があります。

データの整合性

本来、ソフトウェア開発において非正規化はあまり良しとはされていません。その理由の1つはデータの整合性の問題です。

正規化された設計であれば、例えばユーザーの情報が変更になった際もusersテーブルを1箇所更新するだけで済みます。しかし、非正規化されたテーブルでは、過去の数万件の注文履歴に含まれるそのユーザーの情報をすべて更新して回らなければならず、データの不整合が起きるリスクが高まります。

そのため、この手法を採用する場合は、このテーブルを分析専用の、Read Onlyなデータマートとして割り切って運用する必要があるでしょう。

具体的には、次の2点を前提とします。

  • Single Source of Truthとしない: 正となるデータはあくまで正規化された別データベースにあり、このテーブルはその分析用のコピーに過ぎないと位置付ける。
  • 更新処理を行わない: アプリケーションからのリアルタイムなUPDATEやINSERTは許可せず、日次バッチ等を用いて別データベースから洗い替えで生成されるスナップショットとして運用する。

このように、アプリケーションが利用するデータベースと、AIが分析に利用するデータベースでは、それぞれ求められる役割が異なる場合があります。

コストとパフォーマンスのトレードオフ

非正規化テーブルの導入はコストとパフォーマンスに直接的な影響を与えます。導入にあたっては、AIの回答精度だけでなく、インフラコストやレスポンス速度の観点でも検討が必要です。

BigQueryを前提として話を進めますが、非正規化テーブルを用意する際、物理テーブルとして作成する場合は、事前にJOINが済んでいるため、クエリ実行時の計算コストが低く、レスポンスも高速です。一方で、非正規化によりデータが重複して保存されるため、ストレージ料金が増加します。

論理ビューとして作成する場合は、データの実体を重複して持たないため、ストレージ料金の増加を抑えられます。一方、クエリが実行されるたびに内部でJOIN処理が走るため、計算コストが増加し、パフォーマンスが物理テーブルに劣る可能性があります。

重要なのは、分析用のテーブルを用意するというアプローチをとる際に、こうしたコストやパフォーマンスへの影響についてもあらかじめ考慮しておく必要があるということです。

まとめ

本記事では、AIによるデータ分析の精度を高めるアプローチとして、非正規化した分析専用テーブルを用意する戦略を紹介しました。

  • 課題: 正規化されたテーブル構成では、AIが複雑なJOINを含むSQLを生成する必要があり、結合ミス等を誘発しやすい。

  • 解決策: 必要な情報をあらかじめ1つのテーブルにまとめておくことで、AIが生成すべきSQLをシンプルにする。

  • 注意点: データの整合性やコストのトレードオフを考慮し、分析専用の読み取り専用データとして割り切って運用する。

データ分析の民主化を実現するためには、AIモデルの性能に頼るだけでなく、AIがデータを読み解きやすい環境を人間側が整えてあげることも重要です。

We are hiring!

AI・機械学習チームでは、医療現場やWebでの課題解決に取り組むエンジニアを募集しています。

「機械学習モデルの社会実装」や「MLOps基盤の構築・改善」に興味がある方、コスト意識を持った技術選定に関心のある方は、ぜひカジュアル面談でお話ししましょう!

jobs.m3.com