-- Views
November 04, 25
スライド概要
                        【講演内容】
MySQL HeatWave 自然言語SQL生成機能の検証
~ MySQL HeatWave GenAI の新機能の詳細検証と実用性評価 ~
 - NL2SQL 機能について
 - 基本的な使い方
 - 検証ケース①: 類似テーブル/カラム名
 - 検証ケース②: 複数テーブルをまたがる質問
 - 検証ケース③: 想定外の質問の対応
 - 注意点/できないこと
 - 所感
【発表者】
スマート株式会社スタイルデータ
テクノロジー本部
神田智大氏
【イベント情報】
HeatWavejp Meetup #15
https://heatwavejp.connpass.com/event/372575/
                    
HeatWavejpは、MySQL HeatWave の良さを知っていただき、参加者同士でノウハウやナレッジを共有できるユーザーコミュニティです。参加者同士のつながりを深めるため、以下の活動を行ってまいります。 COMMUNICATION *Slackやconnpassを活用したユーザー同士のコミュニケーションの場の提供 EVENT *オンライン/オフラインでのMeetupセミナーや勉強会の開催(隔月程度) SHARING *製品情報や最新アップデート、リリース情報の共有 INTERACT *参加者のコミュニティ・ネットワークやユーザー同士の交流を促進
MySQL HeatWave 自然言語SQL生成機能の検証 MySQL HeatWave GenAIの新機能の詳細検証と実用性評価
自己紹介 • 名前:神田 智大(かんだ ともひろ) • 所属:株式会社スマートスタイル データベースラボ • 最近感動したこと: 奥さんの誕生日に花屋さんにて… NL2SQL “素敵な花束をください” “商品一覧を表示して” 一緒!! SELECT文
目次 1 NL2SQL 機能について 2 基本的な使い方 3 検証ケース①: 類似テーブル/カラム名 4 検証ケース②: 複数テーブルをまたがる質問 5 検証ケース③: 想定外の質問の対応 6 注意点/できないこと 7 所感
NL2SQL 機能について > MySQL HeatWave 9.4.1 で、自然言語でSQLを生成して実行する 機能が実装されました 参考: Changes in MySQL HeatWave 9.4.1
NL2SQL 機能について ③LLMが解釈し、SQLを自動生成 ※構文的に正しい SQL 文が生成されるまで 最大3回まで再試行 ④SQL 文を自動実行・結果セットを表示 ①自然言語でプロンプトを作成 ②表名、列名など関連する データベース・スキーマ・メタデータを自動的に収集 参考:MySQL HeatWaveで自然言語からSQLを実行する新機能 NL2SQL 発表
基本的な使い方 > sys.NL_SQL() プロシージャを使用し、SQL文を生成・実行 プロンプト 出力パラメータ 生成クエリを自動実行をするか 考慮するスキーマ / テーブル 使用するLLM 生成クエリを出力するか メタデータ収集時にコメントを含めるか クエリ生成の再実行をするか 参考: HeatWave ユーザーガイド 10.3.9 NL_SQL
基本的な使い方
mysql> SET @input="どんな商品があるの?商品名の一覧を5件表示して。";
・eccube スキーマを考慮
・LLM は llama 3.3 を指定
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...
|
• 必須パラメータはプロンプトのみ(他引数はNULL省略可)
+---------------------------------------------+
| SELECT name FROM eccube.dtb_product LIMIT 5 |
• デフォルト は生成クエリを表示する/ 自動実行する
+---------------------------------------------+
1 row in set (3.976 sec)
( verbose=1 / execute=true )
・生成クエリが表示
+--------------------------------------------------------+ • 現在選べるモデルは llama シリーズ(3.1, 3.2, 3.3)のみ
| name
|
+--------------------------------------------------------+
| ライムスイカバー
|
| トリコロール・アイス
|
| 太陽の恵みたっぷり!無添加マンゴーアイス
|
| 黄金色の誘惑。濃厚プレミアムパンプキンアイス
|
| お菓子デザート!チョコサンド
|
+--------------------------------------------------------+
生成クエリの実行結果が出力
5 rows in set (2.848 sec)
                                                            基本的な使い方 > meta.llama-3.3-70b-instruct 利用には Oracle Cloud の Generative AI Service との連携が必要です 参考: HeatWave User Guide > 7.5 Authenticate OCI Generative AI Service > 2025/10 現在、日本国内ではGenerative AI Serviceは 大阪リージョン(ap-osaka-1)でのみ提供 参考: Regions with Generative AI
基本的な使い方
>
@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となります
                                                            検証ケースについて • 検証ケース①:類似テーブル / カラム名がある質問対応 • 検証ケース②:複数テーブルをまたがる質問対応 • 検証ケース③:格納データに関連しない想定外の質問対応
検証環境 クラウド環境: Oracle Cloud(大阪リージョン) DBバージョン: MySQL HeatWave Version 9.4.2 検証データ: オープンソースのECサイト構築パッケージ EC-CUBE バージョン4.3のダミーデータを使用
検証ケース①:類似テーブル / カラム名がある質問対応 > 似たようなテーブルを作成し、LLM を混乱させてみる “どんな商品があるの?商品名の一覧を5件表示して。”に対する生成クエリ +---------------------------------------------+ | Executing generated SQL statement... | +---------------------------------------------+ | SELECT name FROM eccube.dtb_product LIMIT 5 | +---------------------------------------------+ ◆正規のテーブル:dtb_products +----+--------------------------------------+------+ | id | name | ... | +----+--------------------------------------+------+ | 1 | 彩のジェラートCUBE | ... | | 2 | 甘酸っぱい誘惑!チェリーアイスサンド | ... | | 3 | みんな大好き!なめらかバニラアイス | ... | | 4 | 新鮮な自家製ブルーベリーのジェラート | ... | | 5 | とろける口どけ。濃厚チョコアイス | ... | +----+--------------------------------------+------+ ◆混乱させるために追加作成するテーブル: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 | +------------+--------------+-------------+------------+
検証ケース①:類似テーブル / カラム名がある質問対応 > 見事に混乱してくれます “どんな商品があるの?商品名の一覧を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) 混乱させるために作成したテーブル(products)が選択される… [恐らく] “商品”を 安直に「products」として解釈したから? (products テーブルには5件しか入ってないのに…) 複数の似た名前のテーブルや列が存在する場合、 LLMに正しい判断をさせるには?
検証ケース①:類似テーブル / カラム名がある質問対応
>
方法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)が選択される
                                                            検証ケース①:類似テーブル / カラム名がある質問対応
>
方法2: テーブルへのコメント付与
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が判別できるようにする
テーブルのコメントを収集し LLM が 判断してくれる
tables オプションも不要になる
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 |
+---------------------------------------------+
正規のテーブル(dtb_product)が選択される
                                                            検証ケース②: 複数のテーブルをまたがる質問 > 複数テーブルを使わないといけない質問をしてみる Q. 「どんな商品があるの?商品名の一覧を5件取得し、値段も表示して」 商品名と値段を同時に得るには dtb_products , dtb_products_class テーブルをJOINする必要がある dtb_products +----+--------------------------------------+------+ | id | name | ... | +----+--------------------------------------+------+ | 1 | 彩のジェラートCUBE | ... | | 2 | 甘酸っぱい誘惑!チェリーアイスサンド | ... | | 3 | みんな大好き!なめらかバニラアイス | ... | | 4 | 新鮮な自家製ブルーベリーのジェラート | ... | | 5 | とろける口どけ。濃厚チョコアイス | ... | +----+--------------------------------------+------+ ECCUBE では price02 列が 画面に表示される 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 | ... | +----+------------+-----------+---------+-----+
検証ケース②: 複数のテーブルをまたがる質問
>
また見事に混乱してくれます
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 |
+--------------------------------------------------------------+
また間違いテーブル(products)が選択される…
+--------------+------------+
| 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 |
+------------+--------------+-------------+------------+
                                                            検証ケース②: 複数のテーブルをまたがる質問
>
方法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なのでダウト
                                                            検証ケース②: 複数のテーブルをまたがる質問
>
方法2: テーブル・カラムへのコメント付与
mysql> ALTER TABLE dtb_product_class COMMENT = '商品価格情報';
mysql> ALTER TABLE dtb_product_class MODIFY COLUMN price02 DECIMAL(12,2) NOT NULL COMMENT '販売価格’;
price02 列にもコメント付与
mysql> SET @input=“どんな商品があるの?商品名の一覧を5件取得し、値段も表示して";
tables オプションを外す
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 |
+-----------------------------------------------------------------------+
テーブル/列のコメントを考慮し、price02 列
が選択される
tables オプションなしでも正しいテーブル
が選択される
                                                            検証ケース②: 複数のテーブルをまたがる質問 > 複雑な要件に対して正しい結果を得るには... - 適切なテーブル/カラム名 - コメントによる説明 - 外部キーの設定 - 実データと整合性のあるキーワードの使用 などの正しくクエリを生成されるためにメタ情報を LLM へ提供することが重要
検証ケース③: 想定外の質問の対応 おもむろに、何の関係もない質問をしてみる 質問例①:明日の新潟の天気は? 質問例②:500円持っていて、210円使っ たら残りはいくら?
検証ケース③: 想定外の質問の対応
>
意図しない質問(天気、算数など)でも必ず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 は生成されるが中身は噓っぱちの場合があるので注意
                                                            検証ケース③: 想定外の質問の対応
mysql> SET @input="500円持ってて、210円のジュースを買いました。残ってるお金は?";
mysql> CALL sys.NL_SQL(@input, @output, JSON_OBJECT('schemas',JSON_ARRAY('eccube'),'model_id','meta.llama3.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文で表現できる計算は可能
                                                            注意点 / できないこと > クエリによっては過剰なリソース消費など意図しない副作用が発生する可能性 ⇒ 対策:クエリ自動実行(execute) を OFF → クエリ表示設定(verbose ) に関わらず生成クエリを表示がされなくなる → @output の JSON データ から生成クエリを引っこ抜くしかない… > 以前の問い合わせや応答結果を利用してクエリ作成はできない • 各問い合わせは独立して動作し、以前のレスポンスを利用されない > 追加 / 更新 / 削除クエリは生成できない • 現時点では SELECT 文のみ生成可能
所感 / 今後の期待 > 所感 • SQLを知らないユーザーでもデータベースから情報を抽出できる革新的機能 > 今後の期待 • クエリ自動実行が ON の場合、大量の結果セットを返すクエリなら LIMIT 句で制限を掛けてほしい • 以前の問い合わせを利用したクエリ生成ができるようになると嬉しい • 日本語に強い LLM がほしい