Oracleの表領域は、足りなくなってから気づくと対応が重くなります。アプリケーションの登録処理が止まる、夜間バッチが途中で落ちる、急いでデータファイル追加を依頼する。こうなると、朝の確認が一気に障害対応になります。
毎朝SQLを手で実行する運用でも確認はできます。ただ、休み明けやリリース直後、月末月初のように見るものが多い日は抜けやすいです。表領域の使用率だけなら、Pythonで取得してメールするくらいの小さな仕組みにしておくと、保守作業が少し楽になります。
ここでは、Oracleの表領域使用率をSQLで取得し、PythonでOK、WARNING、CRITICALに分けてメール送信するサンプルを作ります。WindowsタスクスケジューラとLinuxのcron/systemd timerで毎朝実行するところまで扱います。
サンプル一式は、GitHubの oracle-tablespace-mail に置いています。
使用するバージョンと前提を決める
今回のサンプルは、Python 3.10以上とpython-oracledbを前提にしています。requirements.txtでは次のように指定しています。
oracledb>=2.5,<4python-oracledbは、現在のドキュメントではPython 3.10から3.15を対象にしています。Oracle Database側は19以降で、Thin modeではOracle Database 12.1以降に接続できます。
この記事の検証想定は次です。
| 項目 | 想定 | 補足 |
|---|---|---|
| Python | 3.10以上 | 運用サーバーに入っているPythonが古い場合は先に確認します。 |
| Oracle接続ライブラリ | python-oracledb | 基本はThin modeで接続します。 |
| Oracle Database | 19c以上を主な想定 | 12.1以降でもThin mode接続対象ですが、古い環境は検証してから使います。 |
| 実行環境 | Windows または Linux | Windowsはタスクスケジューラ、Linuxはcronまたはsystemd timerで実行します。 |
| メール送信 | SMTP | 社内SMTPやメールリレーを使う前提です。 |
Python 3.10以上を前提にする
運用サーバーに入っているPythonが3.9以下なら、先にPythonの入れ替え可否を確認します。既存ジョブが同じPythonを使っているサーバーでは、OS標準のPythonを無理に置き換えず、別パスにPythonを入れるか、仮想環境の作り方を分けます。
OS標準のPythonを安易に差し替えると、別の管理コマンドや既存バッチに影響することがあります。 保守サーバーでは、スクリプト単位の仮想環境で閉じる方が扱いやすいです。
Thin modeでつなぐかThick modeが必要か
python-oracledbは、基本的な接続ならOracle Clientを入れずに使えるThin modeで動きます。保守用の小さな監視スクリプトなら、まずThin modeで試すのが始めやすいです。
ただし、古いOracle、特殊な認証、既存のOracle Client設定に依存した接続では、Thick modeが必要になることがあります。接続方式で詰まると表領域監視以前の話になるので、最初に--dry-runでDB接続だけ確認します。
表領域不足を毎朝メールで見つける構成
作る処理は小さく分けます。
1. Oracleへ接続する
2. 表領域使用率SQLを実行する
3. 使用率を80%と90%で判定する
4. 件名と本文を作る
5. SMTPでメールを送る
6. WindowsまたはLinuxで毎朝実行する監視製品の代わりを全部作るわけではありません。ここで作るのは、毎朝の保守確認を忘れにくくするための通知です。表領域の追加、ASMやディスクの空き確認、容量計画まで自動化するものではありません。
メールで十分な範囲を決める
この仕組みが向いているのは、小規模な業務システムや、監視基盤に載せる前の暫定確認です。毎朝の保守メールで、使用率が上がっている表領域を拾えればよい、という範囲に絞ります。
逆に、複数DBをまとめて監視したい、通知先を当番表と連動したい、障害チケットを自動起票したい場合は、このサンプルだけでは足りません。その場合は監視製品やクラウド監視へ寄せた方が後で楽です。
通知後の作業を決めておく
メールが届いたあとに誰が見るかを決めていないと、通知だけ増えます。件名にWARNINGやCRITICALを入れるのは、朝のメール一覧で優先度を見分けるためです。
通知メールは、対応を自動化するものではなく、確認の入口です。メールを受けた人が、対象表領域、増加傾向、AUTOEXTEND、ディスク空きを見るところまでを運用として決めます。
表領域が危険値になったときに、スクリプトが勝手にデータファイルを追加する作りにはしません。通知を受けたあと、対象表領域、AUTOEXTEND、物理ディスク、増加傾向を人が確認してから作業します。
Oracleの表領域使用率をSQLで取得する
表領域の使用率はDBA_TABLESPACE_USAGE_METRICSから取得します。サンプルではDBA_TABLESPACESと結合し、表領域名、種別、状態、使用率、使用MB、最大MBを出しています。
SELECT
m.tablespace_name,
t.contents,
t.status,
ROUND(m.used_percent, 2) AS used_percent,
ROUND(m.used_space * t.block_size / 1024 / 1024, 1) AS used_mb,
ROUND(m.tablespace_size * t.block_size / 1024 / 1024, 1) AS max_mb
FROM
dba_tablespace_usage_metrics m
JOIN dba_tablespaces t
ON t.tablespace_name = m.tablespace_name
ORDER BY
m.used_percent DESC,
m.tablespace_nameused_spaceとtablespace_sizeはブロック数なので、DBA_TABLESPACESのblock_sizeを使ってMBに直しています。メールでは細かいバイト数より、表領域名と使用率、使用MB、最大MBが読めれば十分な場面が多いです。
権限が足りない場合に確認すること
DBA_ビューを参照するため、実行ユーザーに権限が必要です。権限がないユーザーで動かすと、SQL実行時にビューが見えない、または権限エラーになります。
本番では、アプリケーションの接続ユーザーをそのまま使うより、監視用ユーザーを分けた方が扱いやすいです。最低限の参照権限で実行し、更新権限を持たせない構成にします。
AUTOEXTENDの見方を間違えない
DBA_TABLESPACE_USAGE_METRICSの使用率は、表領域がどこまで拡張できるかの影響を受けます。AUTOEXTENDの上限が大きい環境では、現在のデータファイルサイズだけを見た使用率と印象が変わることがあります。
この記事のSQLは、毎朝の入口として使います。WARNINGになったら、表領域の使用率だけで判断せず、データファイルの拡張上限、ASMやディスクの空き、直近の増加量を追加で確認します。
tomo本番DBに接続するスクリプトなので、最初から強い権限のユーザーで動かすのは避けます。表領域を見るだけなら、更新権限はいりません。
Pythonで使用率を判定してメール本文を作る
GitHubのサンプルでは、monitor_tablespaces.pyに処理をまとめています。設定は.envから読みます。
ORACLE_USER=system
ORACLE_PASSWORD=change_me
ORACLE_DSN=localhost:1521/XEPDB1
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=alert@example.com
SMTP_PASSWORD=change_me
SMTP_USE_TLS=true
MAIL_FROM=alert@example.com
MAIL_TO=dba@example.com,system-owner@example.com
WARNING_PERCENT=80
CRITICAL_PERCENT=90
MAIL_ALWAYS=true
LOG_FILE=logs/tablespace-monitor.logパスワードやSMTP情報をPythonファイルに直書きしないためです。.envはGitに入れず、共有するのは.env.exampleだけにします。
Oracleへ接続する処理
接続部分はこの形です。
with oracledb.connect(
user=os.environ["ORACLE_USER"],
password=os.environ["ORACLE_PASSWORD"],
dsn=os.environ["ORACLE_DSN"],
) as connection:
with connection.cursor() as cursor:
cursor.execute(sql)
return [
TablespaceUsage(
name=str(row[0]),
contents=str(row[1]),
status=str(row[2]),
used_percent=float(row[3]),
used_mb=float(row[4]),
max_mb=float(row[5]),
)
for row in cursor
]ORACLE_DSNは環境に合わせます。例えば、サービス名で接続するなら次のような形です。
ORACLE_DSN=db-host.example.local:1521/ORCLPDB180%と90%で状態を分ける
サンプルでは、80%以上をWARNING、90%以上をCRITICALにしています。
def row_status(row: TablespaceUsage, warning_percent: float, critical_percent: float) -> str:
if row.used_percent >= critical_percent:
return "CRITICAL"
if row.used_percent >= warning_percent:
return "WARNING"
return "OK"80%と90%は固定値ではありません。月末に一気に増えるDBなら早めに警告した方がいいですし、AUTOEXTENDの上限が十分にある環境なら、使用率だけで焦ると空振りが増えます。しきい値は、容量の増え方と対応に必要なリードタイムで決めます。
送信前にdry-runで動作確認する
メール送信や本番DB接続をいきなり動かすと、失敗したときの切り分けが面倒です。サンプルには2つの確認方法を入れています。
Oracleなしでメール本文を確認する
--sample --dry-runを使うと、サンプルデータで件名と本文だけを表示します。
python monitor_tablespaces.py --sample --dry-run出力例です。
[CRITICAL] Oracle tablespace usage report 2026-08-01
Oracle tablespace usage report
Checked at: 2026-08-01 08:36:24
Warning: 80.0% / Critical: 90.0%
status tablespace contents used% used_mb max_mb
--------- --------------------- ---------- ------ ----------- ----------
OK USERS PERMANENT 64.2 6420.0 10000.0
WARNING APP_DATA PERMANENT 84.7 16940.0 20000.0
OK APP_INDEX PERMANENT 72.1 7210.0 10000.0
CRITICAL TEMP TEMPORARY 91.3 9130.0 10000.0
OK UNDOTBS1 UNDO 43.5 4350.0 10000.0この段階ではOracleにもSMTPにも接続しません。件名にCRITICALが入るか、表領域名や使用率が読めるかを見ます。
DB接続だけ確認する
Oracleに接続できる環境では、--dry-runでSQL実行と本文作成まで確認します。
python monitor_tablespaces.py --dry-runここで失敗する場合は、だいたい次のどれかです。
ORACLE_DSNが違う
DBサーバーへ通信できない
ユーザー名またはパスワードが違う
DBA_TABLESPACE_USAGE_METRICSを参照できない
python-oracledbがインストールされていないメール送信は最後に確認します。DB接続とSMTP送信を同時に初回確認すると、どちらで落ちたのか追いにくくなります。
Windowsで毎朝実行する
Windowsサーバーなら、タスクスケジューラに登録します。ポイントは、プログラム、引数、開始フォルダを分けることです。
| 項目 | 設定例 |
|---|---|
| プログラム | C:\path\to\nexive-lab\python\oracle-tablespace-mail\.venv\Scripts\python.exe |
| 引数 | C:\path\to\nexive-lab\python\oracle-tablespace-mail\monitor_tablespaces.py |
| 開始 | C:\path\to\nexive-lab\python\oracle-tablespace-mail |
| トリガー | 毎日 8:00 |
| 実行ユーザー | DB接続とログ出力に必要な権限を持つ保守用ユーザー |
開始を空にすると、.envやsql/tablespace_usage.sqlの読み込みで迷うことがあります。サンプルはスクリプトの場所を基準にファイルを読むようにしていますが、タスクスケジューラでは開始フォルダも明示しておく方が確認しやすいです。
実行ユーザーで手動実行する
タスク登録後は、タスクスケジューラの実行ユーザーでコマンドを手動実行します。普段ログインしているユーザーでは動くのに、タスクでは失敗することがあります。
確認するコマンドは次です。
C:\path\to\nexive-lab\python\oracle-tablespace-mail\.venv\Scripts\python.exe C:\path\to\nexive-lab\python\oracle-tablespace-mail\monitor_tablespaces.py --sample --dry-runログ出力先を先に作る
サンプルはLOG_FILE=logs/tablespace-monitor.logにログを出します。フォルダはスクリプト側で作りますが、保守サーバーではログ保存先の権限と容量を先に確認します。
タスクが成功扱いなのにメールが来ない場合は、ログファイルを最初に見ます。 SMTPで失敗したのか、DB接続で失敗したのか、Python自体が起動していないのかを分けるためです。



タスクスケジューラで動かないときは、まず同じ実行ユーザーで手動実行します。設定画面を眺めるより、コマンドを1本ずつ潰す方が早いです。
Linuxで毎朝実行する
Linuxではcronかsystemd timerを使います。既存サーバーでcron運用があるならcronで十分です。systemdでサービス管理を寄せているサーバーなら、timerにしておくと実行履歴をjournalctlで追いやすくなります。
cronで実行する例
毎朝8時に実行する例です。相対パスに頼らず、作業ディレクトリへ移動してから仮想環境のPythonを呼びます。
0 8 * * * cd /opt/nexive-lab/python/oracle-tablespace-mail && /opt/nexive-lab/python/oracle-tablespace-mail/.venv/bin/python monitor_tablespaces.pycronでは、ログインシェルで使っている環境変数やPATHがそのまま入るとは限りません。仮想環境のpythonを絶対パスで指定し、.envはスクリプトと同じディレクトリに置きます。
systemd timerで実行する例
systemdで管理する場合は、serviceとtimerを分けます。
/etc/systemd/system/oracle-tablespace-mail.service:
[Unit]
Description=Oracle tablespace mail monitor
[Service]
Type=oneshot
WorkingDirectory=/opt/nexive-lab/python/oracle-tablespace-mail
ExecStart=/opt/nexive-lab/python/oracle-tablespace-mail/.venv/bin/python monitor_tablespaces.py/etc/systemd/system/oracle-tablespace-mail.timer:
[Unit]
Description=Run Oracle tablespace mail monitor every morning
[Timer]
OnCalendar=*-*-* 08:00:00
Persistent=true
[Install]
WantedBy=timers.target有効化します。
sudo systemctl daemon-reload
sudo systemctl enable --now oracle-tablespace-mail.timer
systemctl list-timers oracle-tablespace-mail.timer実行結果を見るときは次のように確認します。
systemctl status oracle-tablespace-mail.service
journalctl -u oracle-tablespace-mail.servicePersistent=trueを入れておくと、実行予定時刻にサーバーが止まっていた場合の扱いをsystemd側で追いやすくなります。ただし、起動直後にメールが飛ぶのが困る運用なら、ここはサーバーの運用ルールに合わせて調整します。
運用前に確認する注意事項
スクリプトが動くことと、保守運用に入れてよいことは別です。少なくとも次を確認してから毎朝実行に入れます。
| 確認項目 | 見ること | 理由 |
|---|---|---|
| DBユーザー | 参照に必要な権限だけを持っているか | 保守スクリプトに不要な更新権限を持たせないため |
| 接続先 | 本番、検証、待機系を取り違えていないか | 別DBの正常メールを見て安心しないため |
| しきい値 | 80%/90%で足りるか | 増加ペースが速いDBでは警告が遅い場合があるため |
| AUTOEXTEND | 拡張上限と物理ディスクの空きを見るか | 使用率だけでは余裕を読み違えることがあるため |
| TEMP表領域 | 通常表領域と同じ扱いでよいか | 一時的なSQL負荷で上がることがあるため |
| メール経路 | 送信失敗時のログと連絡先を決めているか | 通知の失敗に気づけないと監視にならないため |
| 秘密情報 | .envの権限とバックアップ対象を確認したか | DBパスワードとSMTPパスワードを漏らさないため |
特に接続先の取り違えは怖いです。検証DBを見てOKメールが来ているのに、本番DBの表領域が増え続けていたら意味がありません。メール本文にDB名やホスト名を出す運用にしてもよいです。
本番運用に入れる前に、意図的にWARNING_PERCENTを低くして警告メールが届くことを確認します。 正常時だけ確認して終わると、危険時のメール本文や通知経路が未検証のまま残ります。
TEMP表領域は別枠で見る
TEMP表領域は、重い検索や一時的なソートで使用率が上がることがあります。常に同じ見方で即対応すると、通知が多すぎて誰も見なくなります。
TEMPのCRITICALが続くなら、どのSQLが使っているか、時間帯が偏っているか、バッチ処理と重なっていないかを見ます。通常表領域とTEMP表領域は、メール内では並べて出しても、対応判断は分けた方が無難です。
通知失敗も監視対象にする
メール通知スクリプトは、SMTP接続に失敗するとメールを送れません。つまり、失敗をメールだけで知る作りには限界があります。
Windowsならタスクスケジューラの履歴とログファイル、Linuxならjournalctlやログファイルで失敗を追えるようにします。毎朝メールが来る設定にしておくと、通知が来ないこと自体に気づきやすくなります。



最初の運用では、警告時だけ送るより毎朝送る設定の方が確認しやすいです。何日か回して、本文としきい値が落ち着いてから通知条件を絞ると失敗に気づきやすくなります。
毎朝の確認に入れる前の最終チェック
Oracleの表領域確認は、SQLを1回書ければ終わりではありません。毎朝見るなら、取得、判定、通知、ログ、定期実行までをまとめて確認できる形にします。
今回のサンプルでは、DBA_TABLESPACE_USAGE_METRICSから使用率を取得し、PythonでOK、WARNING、CRITICALに分け、SMTPでメール送信します。--sample --dry-runを使えば、Oracleに接続する前にメール本文の形も確認できます。
Windowsならタスクスケジューラ、Linuxならcronまたはsystemd timerで毎朝実行できます。最初に見るべきなのは、スクリプトの便利さよりも、接続先、権限、しきい値、通知失敗時の扱いです。保守用の自動化は、動くことより、失敗したときに追えることを先に決めると運用に乗せやすくなります。
まずdry-runを残す
初回は--sample --dry-runの出力と、実DBへ接続した--dry-runの出力を作業メモに残します。メール本文の見え方、表領域名、しきい値、ログ出力先を確認した証跡になります。
次に定期実行を1回だけ確認する
タスクスケジューラ、cron、systemd timerのどれを使う場合でも、登録したあとに手動実行します。登録画面や設定ファイルだけを見て終わらせず、実行ユーザー、作業フォルダ、ログ出力、メール送信まで見ます。
最後に運用メモへ落とす
運用メモには、実行時刻、接続先DB、通知先、しきい値、ログファイル、失敗時の確認場所を書きます。スクリプトだけが残っている状態だと、半年後に誰も触れなくなります。


