2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Oracle Database用のMCP Server(sqlcl -mcp)を使ってみる

Last updated at Posted at 2025-07-20

Oracle Database用のCLIクライアントであるsqlclにMCPサーバとして動作する機能が追加されたので使ってみます。

sqlclを直接実行しなくともVS Codeの拡張であるOracle SQL Developer Extension for VS Code経由でも使用できるため、今回はセットアップが簡単なVS Code経由で使用をしてみます。

前提条件

以下のバージョンでsqlcl-mcpオプションが追加されているため、こちらを使用します。

  • sqlcl 25.2以上
    • Oracle SQL Developer Extension for VS Codeの場合は25.2.1以上

sqlclのマニュアル / 25.2のrelease update
https://docs.oracle.com/en/database/oracle/sql-developer-command-line/25.2/sqcug/changes-release-25.2-oracle-sqlcl.html

接続先のDBとしてOracle Databaseが必要となるため、23ai Freeを使用します。
https://container-registry.oracle.com/ords/ocr/ba/database/free

サンプルのスキーマとしてこちらのリポジトリを使用させていただいております。
https://github.com/oracle-samples/db-sample-schemas/tree/main

Coilot Chatで使用するモデルはClaude 3.5 Sonnetとしています。

動作確認

接続用DBの準備

WSL2上で23ai Freeを立てます。(imageが軽いのでlatest-liteを使用していますが、latestでも構いません)
23ai Freeのimageのオプションや操作等は上述の23ai FreeのContainer Registryのページを参照ください。

## imageのpull
$ podman pull container-registry.oracle.com/database/free:latest-lite
$ podman images container-registry.oracle.com/database/free
REPOSITORY                                   TAG          IMAGE ID      CREATED       SIZE
container-registry.oracle.com/database/free  latest-lite  5508cb6f022c  3 months ago  1.67 GB

## サンプルスキーマのリポジトリをclone
$ git clone https://github.com/oracle-samples/db-sample-schemas.git

## imageを起動
$ podman run -d --name ora23ai -p 1521:1521 \
    -v <path to repository>/db-sample-schemas/:/home/oracle/db-sample-schemas/ \
    container-registry.oracle.com/database/free:latest-lite

起動したDB上でサンプルスキーマを導入します。PDB名などは23ai Freeのデフォルトのものを使用しているため、変更している場合は適当に読み替えてください。

## Container上のDBのパスワードを設定
$ podman exec ora23ai ./setPassword.sh <your_password>

## WSL上からContainer上のDBに接続
$ sqlplus pdbadmin/<your_password>@localhost:1521/FREEPDB1

## HRスキーマをインストールする
## HRスキーマのパスワード等の入力を求められるので適当に入力してください
SQL> @/home/oracle/db-sample-schemas/human_resources/hr_install.sql

Oracle SQL Developer拡張の準備

VS Code上でOracle SQL Developerを導入します
https://marketplace.visualstudio.com/items?itemName=Oracle.sql-developer

サイドバーからSQL Developerを選択する
image.png

Crtl+Shift+N で新規のDB接続を追加できるので、以下のような感じで入力する。ここでは接続ユーザをpdbadminにしていますが、先ほど導入したhrユーザでもよいかと思います。
image.png

Copilot ChatからMCPサーバ(SQLcl)の利用

Copilot Chatを開き、「ツールの構成」を表示してMCPサーバ:SQLclが追加されていることを確認する。
image.png

以下のように先ほどSQL Developer上で定義したDB接続に対してクエリを投げるとMCPサーバが動作していることが確認できます。
image.png

run-sqlの折り畳みを展開すると実際に実行されているSQLが確認できます(以下はサンプル)

{
  "mcp_client": "VS Code",
  "model": "Claude 3.5 Sonnet",
  "sql": "SELECT /* LLM in use is Claude 3.5 Sonnet */ \n
    t.table_name,\n
    t.tablespace_name,\n
    t.status,\n
    t.num_rows,\n
    tc.comments as table_comment\n
  FROM all_tables t\n
    LEFT JOIN all_tab_comments tc ON t.owner = tc.owner AND t.table_name = tc.table_name\n
  WHERE t.owner = 'HR'\n
  ORDER BY t.table_name"
}

"TABLE_NAME","TABLESPACE_NAME","STATUS","NUM_ROWS","TABLE_COMMENT"
"COUNTRIES","","VALID",,"country table. References with locations table."
"DEPARTMENTS","SYSTEM","VALID",,"Departments table that shows details of departments where employees
work. references with locations, employees, and job_history tables."
"EMPLOYEES","SYSTEM","VALID",,"employees table. References with departments,
jobs, job_history tables. Contains a self reference."
"JOBS","SYSTEM","VALID",,"jobs table with job titles and salary ranges.
References with employees and job_history table."
"JOB_HISTORY","SYSTEM","VALID",,"Table that stores job history of the employees. If an employee
changes departments within the job or changes jobs within the department,
new rows get inserted into this table with old job information of the
employee. Contains a complex primary key: employee_id+start_date.
References with jobs, employees, and departments tables."
"LOCATIONS","SYSTEM","VALID",,"Locations table that contains specific address of a specific office,
warehouse, and/or production site of a company. Does not store addresses /
locations of customers. references with the departments and countries tables. "
"REGIONS","SYSTEM","VALID",,"Regions table that contains region numbers and names. references with the Countries table."

7行が選択されました。 

MCP経由での問い合わせサンプル

テーブル定義の取得

以下のようにテーブルの定義を聞いてみるとディクショナリビュー等から以下のように情報を収集してくれます。
実行されているSQLを見るに、AIからの可読性が高くなるように適切にコメント分などを入れた方がよいですね。(23aiならAnnotationも見てくれるかも?)

HR.JOBS のテーブル定義は?

image.png

カラムのカーディナリティとアクセスパスの分析

チューニングを目的としたことを聞いてみると、以下のように回答されました。それらしいことを答えてくれますね。

HR.JOBS について各カラムに対する適切なアクセスパスを考えてください。
indexの有無や統計情報上のカーディナリティを考慮して回答してください。

HR.JOBSテーブルの各カラムに対するアクセスパスを分析するため、詳細な統計情報とインデックス情報を取得します。

SQLcl (MCP サーバー)
カラム統計情報を取得します。

SQLcl (MCP サーバー)
別のアプローチで統計情報を取得します。

SQLcl (MCP サーバー)
統計情報が収集されていないようです。実際のデータから各カラムの選択性を分析します。

SQLcl (MCP サーバー)
給与範囲の分布をより詳しく確認します。

SQLcl (MCP サーバー)
SQLcl (MCP サーバー)
インデックス詳細情報も確認します。

SQLcl (MCP サーバー)

HR.JOBSテーブル各カラムの適切なアクセスパス分析

📊 カラム別統計情報とカーディナリティ
カラム名   | ユニーク値数 | 総行数 | 選択性 | NULL | カーディナリティ評価
JOB_ID     |           19 |     19 | 1.0    |      0 |  高(完全ユニーク)
JOB_TITLE  |           19 |     19 | 1.0    |      0 |  高(完全ユニーク)
MIN_SALARY |           14 |     19 | 0.737  |      0 |  中高
MAX_SALARY |           13 |     19 | 0.684  |      0 |  中高

🔍 各カラムに対する推奨アクセスパス
1. JOB_ID カラム
- 現在のインデックス:  JOB_ID_PKUNIQUE, PRIMARY KEY
- 推奨アクセスパス:
  - 等価検索: INDEX UNIQUE SCAN(最適)
  - 範囲検索: INDEX RANGE SCAN
- 理由:
  - 完全にユニークで選択性1.0
  - 主キー制約による一意インデックス存在
  - 単一行アクセスに最適

2. JOB_TITLE カラム
- 現在のインデックス:  なし
- 推奨アクセスパス:
  - 現状: FULL TABLE SCAN
  - 推奨改善: セカンダリインデックス作成を検討
- 検索パターン別推奨:
  - 等価検索: インデックス作成により INDEX UNIQUE SCAN可能
  - LIKE検索: 前方一致なら関数ベースインデックス検討
- 理由:
  - 完全にユニークで選択性1.0
  - 職種名での検索が頻繁なら高いパフォーマンス向上期待

3. MIN_SALARY カラム
- 現在のインデックス:  なし
- 推奨アクセスパス:
  - 現状: FULL TABLE SCAN
  - 範囲検索: インデックス作成によりINDEX RANGE SCAN可能
- 値の分布:
  - 4000: 3件(最頻値)
  - 2500, 4200, 8200: 2
  - その他: 1
- インデックス検討条件:
  - 給与範囲での検索が頻繁な場合
  - WHERE min_salary BETWEEN X AND Y 型クエリが多い場合

4. MAX_SALARY カラム
- 現在のインデックス:  なし
- 推奨アクセスパス:
  - 現状: FULL TABLE SCAN
  - 範囲検索: インデックス作成によりINDEX RANGE SCAN可能
- 値の分布:
  - 9000: 4件(最頻値)
  - 5500, 15000, 16000: 2
  - その他: 1
- インデックス検討条件:
  - 最高給与での絞り込み検索が頻繁な場合

💡 インデックス戦略の提案
現在の状況 (19行の小規模テーブル)

-- 主キーインデックスのみ存在
JOB_ID_PK ON (JOB_ID) -- UNIQUE

推奨追加インデックス (アクセスパターンに応じて)
- JOB_TITLE検索が頻繁な場合:

CREATE INDEX IDX_JOBS_TITLE ON HR.JOBS(JOB_TITLE);

- 給与範囲検索が頻繁な場合:

-- 単一カラム
CREATE INDEX IDX_JOBS_MIN_SAL ON HR.JOBS(MIN_SALARY);
CREATE INDEX IDX_JOBS_MAX_SAL ON HR.JOBS(MAX_SALARY);

-- または複合インデックス
CREATE INDEX IDX_JOBS_SALARY_RANGE ON HR.JOBS(MIN_SALARY, MAX_SALARY);

- 給与範囲での職種検索が頻繁な場合:

CREATE INDEX IDX_JOBS_SAL_TITLE ON HR.JOBS(MIN_SALARY, MAX_SALARY, JOB_TITLE);

⚠️ 注意点
- 小規模テーブル (19) のため、追加インデックスのオーバーヘッドが効果を上回る可能性
- FULL TABLE SCAN でも十分高速な可能性
- インデックス作成は実際のクエリパターンと頻度を分析してから決定すべき
現在の19行という小規模テーブルサイズでは、JOB_IDの主キーインデックス以外は実用上不要である可能性が高いですが、将来の拡張性を考慮した設計が重要です。

自然言語での集計処理の依頼

以下のようにテーブル結合(HR.employee, HR.jobs)を想定した集計処理をさせてみます。

従業員ごとの給与テーブルを取得してください

📊 HR従業員給与テーブル(総合分析)
💰 全体給与統計サマリー
項目	値
総従業員数	107人
最低給与	$2,100
最高給与	$24,000
平均給与	$6,462
中央値給与	$6,200
給与標準偏差	$3,910
歩合制従業員	35人

🏆 高給与トップ10(歩合込み総報酬)
順位	従業員ID	氏名	職種	基本給	歩合率	総報酬	部署
1	100	Steven King	President	$24,000	-	$24,000	Executive
2	145	John Singh	Sales Manager	$14,000	40%	$19,600	Sales
3	146	Karen Partners	Sales Manager	$13,500	30%	$17,550	Sales
4	101	Neena Yang	Admin VP	$17,000	-	$17,000	Executive
5	102	Lex Garcia	Admin VP	$17,000	-	$17,000	Executive
6	147	Alberto Errazuriz	Sales Manager	$12,000	30%	$15,600	Sales
7	168	Lisa Ozer	Sales Rep	$11,500	25%	$14,375	Sales
8	174	Ellen Abel	Sales Rep	$11,000	30%	$14,300	Sales
9	148	Gerald Cambrault	Sales Manager	$11,000	30%	$14,300	Sales
10	156	Janette King	Sales Rep	$10,000	35%	$13,500	Sales

🏢 部署別給与統計
部署名	従業員数	最低給与	最高給与	平均給与	中央値	総人件費
Executive	3	$17,000	$24,000	$19,333	$17,000	$58,000
Accounting	2	$8,300	$12,008	$10,154	$10,154	$20,308
Public Relations	1	$10,000	$10,000	$10,000	$10,000	$10,000
Marketing	2	$6,000	$13,000	$9,500	$9,500	$19,000
Sales	34	$6,100	$14,000	$8,956	$8,900	$304,500
Finance	6	$6,900	$12,008	$8,601	$8,000	$51,608
IT	5	$4,200	$9,000	$5,760	$4,800	$28,800
Human Resources	1	$6,500	$6,500	$6,500	$6,500	$6,500
Administration	1	$4,400	$4,400	$4,400	$4,400	$4,400
Purchasing	6	$2,500	$11,000	$4,150	$2,850	$24,900
Shipping	45	$2,100	$8,200	$3,476	$3,100	$156,400

📈 重要な洞察
💡 給与構造の特徴
- 幹部層: Executive部署が最高平均給与($19,333)
- 営業部門: Sales部署は最大人数(34人)で歩合制が一般的
- オペレーション: Shipping部署が最多人数(45人)だが低給与レンジ
- 歩合制: 35人(約33%)が歩合制を適用、主に営業職

🎯 給与分析ポイント
- 給与格差: 最高給与は最低給与の11.4倍($24,000 vs $2,100)
- 部署間格差: 最高平均部署は最低平均部署の5.6倍
- 歩合効果: 営業職では歩合により実質収入が大幅増加

この分析により、組織の給与体系と人件費構造が明確に把握できます。

ログを見るとこの問い合わせでは以下のようなSQLを実行しています。
テーブルやカラムに適切にコメントが入れられており、外部キー制約などから関係性が読み取れる状態であればこのぐらいのSQLは書けるみたいですね。

SELECT /* LLM in use is Claude 3.5 Sonnet */
       employee_id,
       first_name,
       last_name,
       job_id,
       salary,
       commission_pct,
       hire_date,
       department_id
FROM HR.EMPLOYEES
ORDER BY salary DESC NULLS LAST

SELECT /* LLM in use is Claude 3.5 Sonnet */
       e.employee_id,
       e.first_name || ' ' || e.last_name as full_name,
       j.job_title,
       e.salary,
       e.commission_pct,
       CASE 
           WHEN e.commission_pct IS NOT NULL 
           THEN e.salary + (e.salary * e.commission_pct)
           ELSE e.salary
       END as total_compensation,
       d.department_name,
       e.hire_date,
       ROUND(MONTHS_BETWEEN(SYSDATE, e.hire_date)/12, 1) as years_employed
FROM HR.EMPLOYEES e
JOIN HR.JOBS j ON e.job_id = j.job_id
LEFT JOIN HR.DEPARTMENTS d ON e.department_id = d.department_id
ORDER BY total_compensation DESC NULLS LAST

SELECT /* LLM in use is Claude 3.5 Sonnet */
       COUNT(*) as total_employees,
       MIN(salary) as min_salary,
       MAX(salary) as max_salary,
       ROUND(AVG(salary), 2) as avg_salary,
       ROUND(MEDIAN(salary), 2) as median_salary,
       ROUND(STDDEV(salary), 2) as salary_stddev,
       COUNT(CASE WHEN commission_pct IS NOT NULL THEN 1 END) as employees_with_commission
FROM HR.EMPLOYEES

SELECT /* LLM in use is Claude 3.5 Sonnet */
       COALESCE(d.department_name, 'No Department') as department_name,
       COUNT(*) as employee_count,
       MIN(e.salary) as min_salary,
       MAX(e.salary) as max_salary,
       ROUND(AVG(e.salary), 0) as avg_salary,
       ROUND(MEDIAN(e.salary), 0) as median_salary,
       SUM(e.salary) as total_salary_cost
FROM HR.EMPLOYEES e
LEFT JOIN HR.DEPARTMENTS d ON e.department_id = d.department_id
GROUP BY d.department_name
ORDER BY avg_salary DESC
2
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?