Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[HeatWavejpMeetup#15] 自然言語からSQL生成(NL2SQL)機能検証レポ...

[HeatWavejpMeetup#15] 自然言語からSQL生成(NL2SQL)機能検証レポート [神田 智大 氏 (スマートスタイル)]

【講演内容】
MySQL HeatWave 自然言語SQL生成機能の検証
~ MySQL HeatWave GenAIの新機能の詳細検証と実用性評価 ~

 - NL2SQL 機能について
 - 基本的な使い方
 - 検証ケース①: 類似テーブル/カラム名
 - 検証ケース②: 複数テーブルをまたがる質問
 - 検証ケース③: 想定外の質問の対応
 - 注意点/できないこと
 - 所感

【発表者】
株式会社スマートスタイル
データテクノロジー本部
神田 智大 氏

【イベント情報】
HeatWavejp Meetup #15
https://heatwavejp.connpass.com/event/372575/

More Decks by HeatWavejp(MySQL HeatWave Japan User Group)

Other Decks in Technology

Transcript

  1. 自己紹介 • 名前:神田 智大(かんだ ともひろ) • 所属:株式会社スマートスタイル データベースラボ • 最近感動したこと:

    奥さんの誕生日に花屋さんにて… SELECT文 “商品一覧を表示して” “素敵な花束をください” NL2SQL 一緒!!
  2. 基本的な使い方 sys.NL_SQL() プロシージャを使用し、SQL文を生成・実行 参考: HeatWave ユーザーガイド 10.3.9 NL_SQL > 生成クエリを自動実行をするか

    考慮するスキーマ / テーブル 使用するLLM メタデータ収集時にコメントを含めるか クエリ生成の再実行をするか 生成クエリを出力するか プロンプト 出力パラメータ
  3. mysql> SET @input="どんな商品があるの?商品名の一覧を5件表示して。"; mysql> CALL sys.NL_SQL(@input, @output, JSON_OBJECT( 'schemas',JSON_ARRAY('eccube’), 'model_id','meta.llama-3.3-70b-instruct’));

    +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT name FROM eccube.dtb_product LIMIT 5 | +---------------------------------------------+ 1 row in set (3.976 sec) +--------------------------------------------------------+ | name | +--------------------------------------------------------+ | ライムスイカバー | | トリコロール・アイス | | 太陽の恵みたっぷり!無添加マンゴーアイス | | 黄金色の誘惑。濃厚プレミアムパンプキンアイス | | お菓子デザート!チョコサンド | +--------------------------------------------------------+ 5 rows in set (2.848 sec) 基本的な使い方 • 必須パラメータはプロンプトのみ(他引数はNULL省略可) • デフォルト は生成クエリを表示する/ 自動実行する ( verbose=1 / execute=true ) • 現在選べるモデルは llama シリーズ(3.1, 3.2, 3.3)のみ ・生成クエリが表示 ・eccube スキーマを考慮 ・LLM は llama 3.3 を指定 生成クエリの実行結果が出力
  4. 2025/10 現在、日本国内ではGenerative AI Serviceは 大阪リージョン(ap-osaka-1)でのみ提供 基本的な使い方 meta.llama-3.3-70b-instruct 利用には Oracle Cloud

    の Generative AI Service との連携が必要です > > 参考: HeatWave User Guide > 7.5 Authenticate OCI Generative AI Service 参考: Regions with Generative AI
  5. 基本的な使い方 @output の内容は以下の通り > mysql> SELECT JSON_PRETTY(@output)¥G ********************* 1. row

    ********************** JSON_PRETTY(@output): { "tables": [ "eccube.customers", "eccube.daily_product_class_sales_data", "eccube.dtb_authority_role", ・・・(省略) ], "schemas": [ "eccube" ], "model_id": "meta.llama-3.3-70b-instruct", "sql_query": "SELECT `name` FROM `eccube`.`dtb_product` ORDER BY RAND() LIMIT 5", "is_sql_valid": 1 } 出力項目 内容 tables,schemas 考慮されたテーブル/データベースの リスト model_id 使用したLLMのモデルID sql_query 生成されたSQL is_sql_valid 生成されたSQLが有効化かどうか (0:無効 / 1:有効) ※ NL_SQL()でuse_retry=false 設定時、生成した SQLの実行に失敗すると0となります
  6. 検証環境 クラウド環境: Oracle Cloud(大阪リージョン) DBバージョン: MySQL HeatWave Version 9.4.2 検証データ:

    オープンソースのECサイト構築パッケージ EC-CUBE バージョン4.3のダミーデータを使用
  7. 検証ケース①:類似テーブル / カラム名がある質問対応 ◆混乱させるために追加作成するテーブル:products +------------+--------------+-------------+------------+ | product_id | product_name |

    category | unit_price | +------------+--------------+-------------+------------+ | 1 | Laptop | Electronics | 1000.00 | | 2 | Book | Books | 20.00 | | 3 | Shirt | Clothing | 50.00 | | 4 | Laptop | Electronics | 1000.00 | | 5 | Book | Books | 20.00 | +------------+--------------+-------------+------------+ ◆正規のテーブル:dtb_products +----+--------------------------------------+------+ | id | name | ... | +----+--------------------------------------+------+ | 1 | 彩のジェラートCUBE | ... | | 2 | 甘酸っぱい誘惑!チェリーアイスサンド | ... | | 3 | みんな大好き!なめらかバニラアイス | ... | | 4 | 新鮮な自家製ブルーベリーのジェラート | ... | | 5 | とろける口どけ。濃厚チョコアイス | ... | +----+--------------------------------------+------+ “どんな商品があるの?商品名の一覧を5件表示して。”に対する生成クエリ +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT name FROM eccube.dtb_product LIMIT 5 | +---------------------------------------------+ 似たようなテーブルを作成し、LLM を混乱させてみる >
  8. “どんな商品があるの?商品名の一覧を5件表示して。”に対する生成クエリ +------------------------------------------------------------------+ | Executing generated SQL statement... | +------------------------------------------------------------------+ |

    SELECT product_name FROM eccube.products ORDER BY RAND() LIMIT 5 | +------------------------------------------------------------------+ 1 row in set (10.791 sec) +--------------+ | product_name | +--------------+ | Book | | Book | | Laptop | | Laptop | | Shirt | +--------------+ 5 rows in set (10.791 sec) 検証ケース①:類似テーブル / カラム名がある質問対応 見事に混乱してくれます > 複数の似た名前のテーブルや列が存在する場合、 LLMに正しい判断をさせるには? [恐らく] “商品”を 安直に「products」として解釈したから? (products テーブルには5件しか入ってないのに…) 混乱させるために作成したテーブル(products)が選択される…
  9. 検証ケース①:類似テーブル / カラム名がある質問対応 方法1: tables オプションで明示的にテーブルを指定する > mysql> CALL sys.NL_SQL(@input,

    @output, JSON_OBJECT('tables',JSON_ARRAY( JSON_OBJECT('schema_name', 'eccube','table_name', 'dtb_product’)), 'model_id','meta.llama-3.3-70b-instruct’)); “どんな商品があるの?商品名の一覧を5件表示して。” に対する生成クエリ +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT name FROM eccube.dtb_product LIMIT 5 | +---------------------------------------------+ 結果の精度は上がる 実行者がスキーマの内容を理解する必要がある パラメータを実行時に変更する必要がある 考慮するテーブルを指定 正規のテーブル(dtb_product)が選択される
  10. mysql> ALTER TABLE dtb_product COMMENT = '商品情報'; mysql> ALTER TABLE

    products COMMENT = '商品カテゴリ情報’; mysql> SHOW CREATE TABLE dtb_product¥G ********************** 1. row ****************** Create Table: CREATE TABLE `dtb_product` ( : ) ENGINE=InnoDB COMMENT='商品情報’ mysql> SHOW CREATE TABLE products¥G ********************** 1. row ******************* Create Table: CREATE TABLE `products` ( : ) ENGINE=InnoDB COMMENT='商品カテゴリ情報' テーブルのコメントを収集し LLM が 判断してくれる 検証ケース①:類似テーブル / カラム名がある質問対応 方法2: テーブルへのコメント付与 > CALL sys.NL_SQL( @input, @output, JSON_OBJECT( 'schemas',JSON_ARRAY('eccube’), 'model_id','meta.llama-3.3-70b-instruct’)); +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT name FROM eccube.dtb_product LIMIT 5 | +---------------------------------------------+ クエリ生成時、テーブル に付与された コメントからLLMが判別できるようにする 正規のテーブル(dtb_product)が選択される tables オプションも不要になる
  11. 検証ケース②: 複数のテーブルをまたがる質問 Q. 「どんな商品があるの?商品名の一覧を5件取得し、値段も表示して」 複数テーブルを使わないといけない質問をしてみる > dtb_products +----+--------------------------------------+------+ | id

    | name | ... | +----+--------------------------------------+------+ | 1 | 彩のジェラートCUBE | ... | | 2 | 甘酸っぱい誘惑!チェリーアイスサンド | ... | | 3 | みんな大好き!なめらかバニラアイス | ... | | 4 | 新鮮な自家製ブルーベリーのジェラート | ... | | 5 | とろける口どけ。濃厚チョコアイス | ... | +----+--------------------------------------+------+ dtb_products_class +----+------------+-----------+---------+-----+ | id | product_id | price01 | price02 | ... | +----+------------+-----------+---------+-----+ | 1 | 1 | 115000.00 | 1200.00 | ... | | 11 | 2 | 3000.00 | 380.00 | ... | | 15 | 3 | NULL | 500.00 | ... | | 19 | 4 | NULL | 450.00 | ... | | 23 | 5 | NULL | 620.00 | ... | +----+------------+-----------+---------+-----+ 商品名と値段を同時に得るには dtb_products , dtb_products_class テーブルをJOINする必要がある ECCUBE では price02 列が 画面に表示される
  12. mysql> SET @input="どんな商品があるの?商品名の一覧を5件取得し、値段も表示して。"; mysql> CALL sys.NL_SQL(@input, @output, JSON_OBJECT('schemas',JSON_ARRAY('eccube’))); +--------------------------------------------------------------+ |

    Executing generated SQL statement... | +--------------------------------------------------------------+ | SELECT product_name, unit_price FROM eccube.products LIMIT 5 | +--------------------------------------------------------------+ +--------------+------------+ | product_name | unit_price | +--------------+------------+ | Laptop | 1000.00 | | Book | 20.00 | | Shirt | 50.00 | | Laptop | 1000.00 | | Book | 20.00 | +--------------+------------+ 検証ケース②: 複数のテーブルをまたがる質問 [恐らく] products テーブルから商品名(product_name)と 価格(unit_price) が結合なしには得られるから? products +------------+--------------+-------------+------------+ | product_id | product_name | category | unit_price | +------------+--------------+-------------+------------+ | 1 | Laptop | Electronics | 1000.00 | +------------+--------------+-------------+------------+ また見事に混乱してくれます > また間違いテーブル(products)が選択される…
  13. 検証ケース②: 複数のテーブルをまたがる質問 方法1: tables オプションで明示的にテーブルを指定してみる > mysql> CALL sys.NL_SQL(@input, @output,

    JSON_OBJECT('tables',JSON_ARRAY( JSON_OBJECT('schema_name', 'eccube', 'table_name', 'dtb_product’), JSON_OBJECT('schema_name', 'eccube', 'table_name', 'dtb_product_class')), 'model_id','meta.llama-3.3-70b-instruct’)); “どんな商品があるの?商品名の一覧を5件取得し、値段も表示して。”に対する生成クエリ +----------------------------------------------------------------------+ | Executing generated SQL | +----------------------------------------------------------------------+ | SELECT T1.name, T2.price01 FROM eccube.dtb_product AS T1 JOIN eccube.dtb_product_class AS T2 ON T1.id = T2.product_id LIMIT 5 | +----------------------------------------------------------------------+ +--------------------------------------------------------+-----------+ | name | price01 | +--------------------------------------------------------+-----------+ | 彩のジェラートCUBE | 115000.00 | | 甘酸っぱい誘惑!チェリーアイスサンド | 3000.00 | | みんな大好き!なめらかバニラアイス | NULL | | 新鮮な自家製ブルーベリーのジェラート | NULL | | とろける口どけ。濃厚チョコアイス | NULL | +--------------------------------------------------------+-----------+ 正しいテーブルが選択される ECCUBEの画面に表示される価格情報は price01ではなくprice02なのでダウト 考慮するテーブルを指定
  14. mysql> ALTER TABLE dtb_product_class COMMENT = '商品価格情報'; mysql> ALTER TABLE

    dtb_product_class MODIFY COLUMN price02 DECIMAL(12,2) NOT NULL COMMENT '販売価格’; mysql> SET @input=“どんな商品があるの?商品名の一覧を5件取得し、値段も表示して"; mysql> CALL sys.NL_SQL(@input, @output, JSON_OBJECT(‘schemas’,JSON_ARRAY(‘eccube’), 'model_id','meta.llama-3.3-70b-instruct’)); +-----------------------------------------------------------------------+ | Executing generated SQL statement... | +-----------------------------------------------------------------------+ | SELECT T1.name, T2.price02 FROM eccube.dtb_product AS T1 JOIN eccube.dtb_product_class AS T2 ON T1.id = T2.product_id LIMIT 5 | +-----------------------------------------------------------------------+ 検証ケース②: 複数のテーブルをまたがる質問 方法2: テーブル・カラムへのコメント付与 > price02 列にもコメント付与 テーブル/列のコメントを考慮し、price02 列 が選択される tables オプションなしでも正しいテーブル が選択される tables オプションを外す
  15. 検証ケース②: 複数のテーブルをまたがる質問 複雑な要件に対して正しい結果を得るには... - 適切なテーブル/カラム名 - コメントによる説明 - 外部キーの設定 -

    実データと整合性のあるキーワードの使用 などの正しくクエリを生成されるためにメタ情報を LLM へ提供することが重要 >
  16. 検証ケース③: 想定外の質問の対応 意図しない質問(天気、算数など)でも必ずSQLが生成される挙動を確認しました。 テーブルと無関係な質問でも常にSQL文が生成されます。 mysql> SET @input=“明日の新潟の天気は?"; mysql> CALL sys.NL_SQL(@input,

    @output, JSON_OBJECT('schemas',JSON_ARRAY('eccube’)) +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT title FROM eccube.dtb_calendar WHERE holiday = CURDATE() + INTERVAL ‘1’ DAY AND title = ‘新潟‘ +---------------------------------------------+ 1 row in set (5.51 sec) Empty set (5.51 sec) Query OK, 0 rows affected (5.52 sec) SQL は生成されるが中身は噓っぱちの場合があるので注意 >
  17. 検証ケース③: 想定外の質問の対応 mysql> SET @input="500円持ってて、210円のジュースを買いました。残ってるお金は?"; mysql> CALL sys.NL_SQL(@input, @output, JSON_OBJECT('schemas',JSON_ARRAY('eccube'),'model_id','meta.llama-

    3.3-70b-instruct’)); +-------------------------------------+ | Executing generated SQL statement...| +-------------------------------------+ | SELECT 500 - 210 AS remaining_money | +-------------------------------------+ 1 row in set (2.74 sec) +-----------------+ | remaining_money | +-----------------+ | 290 | +-----------------+ 1 row in set (2.74 sec) SELECT文で表現できる計算は可能
  18. 注意点 / できないこと クエリによっては過剰なリソース消費など意図しない副作用が発生する可能性 ⇒ 対策:クエリ自動実行(execute) を OFF → クエリ表示設定(verbose

    ) に関わらず生成クエリを表示がされなくなる → @output の JSON データ から生成クエリを引っこ抜くしかない… 以前の問い合わせや応答結果を利用してクエリ作成はできない • 各問い合わせは独立して動作し、以前のレスポンスを利用されない 追加 / 更新 / 削除クエリは生成できない • 現時点では SELECT 文のみ生成可能 > > >
  19. 所感 / 今後の期待 • SQLを知らないユーザーでもデータベースから情報を抽出できる革新的機能 所感 > 今後の期待 > •

    クエリ自動実行が ON の場合、大量の結果セットを返すクエリなら LIMIT 句で制限を掛けてほしい • 以前の問い合わせを利用したクエリ生成ができるようになると嬉しい • 日本語に強い LLM がほしい