MySQL - イベントスケジューラ
概要
MySQLのイベントスケジューラは、データベース内でスケジュール済みタスクを自動実行する機能である。
これは、cronのようなスケジューリング機能をMySQL内で提供するものであり、定期的なメンテナンスやデータ整理、集計処理を自動化できる。
イベントスケジューラは、MySQL 5.1以降で利用可能である。
イベントには、1度限り実行される ATイベント と、繰り返し実行される EVERYイベント の2種類がある。
- ATイベント
- 指定された日時に1度だけ実行される。
- EVERYイベント
- 指定された間隔で繰り返し実行される。
イベントスケジューラは、event_scheduler システム変数によって制御される。
この変数は、ON、OFF、DISABLEDの3つの状態を持ち、ランタイムで切り替えが可能である。(DISABLEDを除く)
イベントは、CREATE EVENT 文で作成し、ALTER EVENT 文で変更し、DROP EVENT 文で削除する。
イベントの情報は、INFORMATION_SCHEMA.EVENTS テーブルから確認できる。
イベントスケジューラの主な用途には、古いログの定期削除、集計テーブルの更新、テーブル最適化、バックアップ処理等がある。
SQL内で完結するため、外部スクリプトが不要であり、OS非依存で移植性が高いという利点がある。
イベントスケジューラの有効化
event_scheduler変数
イベントスケジューラの動作は、event_scheduler システム変数で制御される。
この変数には、以下の3つの状態がある。
br>
| 状態 | 説明 |
|---|---|
| ON (または 1) | イベントスケジューラが有効であり、イベントが実行可能な状態である。 スケジューラスレッドが起動し、 SHOW PROCESSLIST に表示される。
|
| OFF (または 0) | イベントスケジューラが無効であり、イベントは実行されない。 スレッドは停止しているが、ランタイムでONに切り替え可能である。 |
| DISABLED | イベントスケジューラが完全に無効化されている。 サーバ起動時のみ設定可能であり、ランタイムでは変更できない。 |
イベントスケジューラをランタイムで有効化する構文を以下に示す。
SET GLOBAL event_scheduler = ON;
サーバ起動時にイベントスケジューラを有効化するには、my.cnfファイル に以下に示す設定を追加する。
[mysqld]
event_scheduler = ON
状態の確認
イベントスケジューラの現在の状態を確認する方法を以下に示す。
SHOW VARIABLES LIKE 'event_scheduler';
または、グローバル変数を直接参照する。
SELECT @@GLOBAL.event_scheduler;
イベントスケジューラスレッドが起動しているかどうかを確認する。
SHOW PROCESSLIST;
event_scheduler が ON の場合、User が event_scheduler、Command が Daemon のプロセスが表示される。
イベントの作成
基本構文
イベントを作成するには、CREATE EVENT 文を使用する。
CREATE
[DEFINER = <ユーザ名>]
EVENT [IF NOT EXISTS] <イベント名>
ON SCHEDULE <スケジュール>
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'string']
DO <イベント本体>;
下表に、主要な構文要素を示す。
| 構文要素 | 説明 |
|---|---|
| DEFINER | イベントを実行するユーザを指定する。 省略時は、現在のユーザが設定される。 |
| IF NOT EXISTS | 同名のイベントが存在する場合、エラーにならず警告のみが出力される。 |
| ON SCHEDULE | イベントの実行スケジュールを指定する。 |
| ON COMPLETION | イベント実行完了後の動作を指定する。 |
| ENABLE / DISABLE | イベントの有効・無効を指定する。 |
| COMMENT | イベントのコメントを指定する。 |
| DO | 実行するSQL文 または ストアドプロシージャを指定する。 |
スケジュール指定
イベントのスケジュールは、ON SCHEDULE 句で指定する。
schedule: {
AT <タイムスタンプ> [+ INTERVAL <間隔>] ...
| EVERY <間隔>
[STARTS <タイムスタンプ> [+ INTERVAL <間隔>] ...]
[ENDS <タイムスタンプ> [+ INTERVAL <間隔>] ...]
}
interval:
<数値> {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
AT構文は、1度限りのイベントを作成する。
CREATE EVENT cleanup_event
ON SCHEDULE AT '2026-03-01 03:00:00'
DO DELETE FROM logs WHERE created_date < NOW() - INTERVAL 30 DAY;
現在時刻からの相対時刻で指定することもできる。
CREATE EVENT temp_event
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO INSERT INTO status_log (message) VALUES ('Hourly check');
EVERY構文は、繰り返しイベントを作成する。
CREATE EVENT daily_cleanup
ON SCHEDULE EVERY 1 DAY
DO DELETE FROM logs WHERE created_date < NOW() - INTERVAL 30 DAY;
STARTS と ENDS を使用して、開始日時と終了日時を指定できる。
CREATE EVENT monthly_report
ON SCHEDULE EVERY 1 MONTH
STARTS '2026-01-01 00:00:00'
ENDS '2026-12-31 23:59:59'
DO CALL generate_monthly_report();
様々な間隔の指定例を以下に示す。
-- 毎時間実行
ON SCHEDULE EVERY 1 HOUR
-- 15分ごとに実行
ON SCHEDULE EVERY 15 MINUTE
-- 毎週月曜日 (1週間ごと) に実行
ON SCHEDULE EVERY 1 WEEK
STARTS '2026-02-17 00:00:00'
-- 3時間ごとに実行
ON SCHEDULE EVERY 3 HOUR
-- 30秒ごとに実行
ON SCHEDULE EVERY 30 SECOND
ON COMPLETION
ON COMPLETION 句は、イベント実行完了後の動作を制御する。
| オプション | 説明 |
|---|---|
| PRESERVE | イベント実行完了後も、イベント定義を保持する。 1度限りイベントでも、実行後に削除されない。 |
| NOT PRESERVE | イベント実行完了後、イベント定義を自動削除する。(デフォルト) 1度限りイベントは、実行後に自動的に削除される。 |
1度限りイベントを実行後も保持する例を以下に示す。
CREATE EVENT one_time_event
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
ON COMPLETION PRESERVE
DO INSERT INTO maintenance_log (message) VALUES ('Scheduled maintenance');
繰り返しイベントは、ENDS で指定された終了日時を過ぎると完了とみなされる。
NOT PRESERVE を指定すると、終了日時後にイベント定義が削除される。
イベントの状態
イベントの有効・無効状態を指定できる。
| オプション | 説明 |
|---|---|
| ENABLE | イベントを有効化する。(デフォルト) |
| DISABLE | イベントを無効化する。 イベント定義は保持されるが、実行されない。 |
| DISABLE ON SLAVE | レプリケーション環境でレプリカ側では無効化する。 マスタ側でのみ実行される。 |
無効状態でイベントを作成する例を以下に示す。
CREATE EVENT maintenance_event
ON SCHEDULE EVERY 1 DAY
DISABLE
COMMENT 'メンテナンス用イベント (手動有効化が必要)'
DO CALL maintenance_procedure();
イベントの実行内容
単一SQL文
DO 句には、単一のSQL文を記述できる。
CREATE EVENT delete_old_logs
ON SCHEDULE EVERY 1 DAY
DO DELETE FROM logs WHERE date < NOW() - INTERVAL 30 DAY;
INSERT文 や UPDATE文も使用できる。
CREATE EVENT update_statistics
ON SCHEDULE EVERY 1 HOUR
DO UPDATE stats SET last_update = CURRENT_TIMESTAMP;
複数SQL文
複数のSQL文を実行する場合は、BEGIN ... END ブロックを使用する。
デリミタを変更して、ブロック内のセミコロンと区別する必要がある。
DELIMITER |
CREATE EVENT cleanup_and_optimize
ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 03:00:00'
DO BEGIN
DELETE FROM logs WHERE created_date < NOW() - INTERVAL 30 DAY;
OPTIMIZE TABLE logs;
END |
DELIMITER ;
変数やループを使用した複雑な処理も記述できる。
以下の例では、10回に分けて1000行ずつ削除し、各削除の間に1秒の待機時間を設けている。
これにより、データベースへの負荷を分散できる。
DELIMITER |
CREATE EVENT batch_delete
ON SCHEDULE EVERY 1 DAY
DO BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 10 DO
DELETE FROM logs WHERE created_date < NOW() - INTERVAL 90 DAY LIMIT 1000;
SET i = i + 1;
DO SLEEP(1);
END WHILE;
END |
DELIMITER ;
ストアドプロシージャの呼び出し
DO 句でストアドプロシージャを呼び出すこともできる。
CREATE EVENT daily_maintenance
ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 02:00:00'
DO CALL cleanup_procedure();
パラメータを渡すこともできる。
CREATE EVENT monthly_archive
ON SCHEDULE EVERY 1 MONTH
DO CALL archive_old_data(90);
イベントの変更
既存のイベントを変更するには、ALTER EVENT 文を使用する。
ALTER [DEFINER = <ユーザ名>] EVENT <イベント名>
[ON SCHEDULE <スケジュール>]
[ON COMPLETION [NOT] PRESERVE]
[RENAME TO <新しいイベント名>]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'string']
[DO <イベント本体>]
- スケジュールを変更する例
ALTER EVENT cleanup_event ON SCHEDULE EVERY 2 DAY;
- イベントを無効化する例
ALTER EVENT maintenance_event DISABLE;
- イベントを有効化する例
ALTER EVENT maintenance_event ENABLE;
- イベント名を変更する例
ALTER EVENT old_event_name RENAME TO new_event_name;
- 実行内容を変更する例
ALTER EVENT cleanup_event DO DELETE FROM logs WHERE created_date < NOW() - INTERVAL 60 DAY;
- 複数の項目を同時に変更することもできる。
ALTER EVENT maintenance_event ON SCHEDULE EVERY 1 WEEK ON COMPLETION PRESERVE COMMENT '毎週実行されるメンテナンスイベント';
イベントの削除
イベントを削除するには、DROP EVENT 文を使用する。
DROP EVENT [IF EXISTS] <イベント名>;
イベントを削除する例を以下に示す。
DROP EVENT cleanup_event;
IF EXISTS 句を使用すると、イベントが存在しない場合でもエラーにならず、警告のみが出力される。
DROP EVENT IF EXISTS temp_event;
イベントの確認
イベント一覧を確認するには、SHOW EVENTS 文を使用する。
SHOW EVENTS;
- 特定のデータベースのイベントを確認する。
SHOW EVENTS FROM <データベース名>;
- パターンマッチングでイベントを検索する。
SHOW EVENTS LIKE 'cleanup%';
- 特定のイベントの定義を確認するには、
SHOW CREATE EVENT文を使用する。SHOW CREATE EVENT <イベント名>;
- イベントの詳細情報は、
INFORMATION_SCHEMA.EVENTSテーブルから取得できる。SELECT EVENT_SCHEMA, EVENT_NAME, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STARTS, ENDS, STATUS, ON_COMPLETION, LAST_EXECUTED FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'cleanup_event';
| カラム名 | 説明 |
|---|---|
EVENT_SCHEMA |
イベントが属するデータベース名 |
EVENT_NAME |
イベント名 |
DEFINER |
イベントの定義者 |
EVENT_TYPE |
ONE TIME または RECURRING |
EXECUTE_AT |
一度限りイベントの実行日時 |
INTERVAL_VALUE |
繰り返しイベントの間隔値 |
INTERVAL_FIELD |
繰り返しイベントの間隔単位 (HOUR、DAY等) |
STARTS |
繰り返しイベントの開始日時 |
ENDS |
繰り返しイベントの終了日時 |
STATUS |
ENABLED、DISABLED、SLAVESIDE_DISABLED |
ON_COMPLETION |
PRESERVE または NOT PRESERVE |
LAST_EXECUTED |
最後に実行された日時 |
全てのイベントの実行状態を確認する。
SELECT EVENT_NAME, STATUS, LAST_EXECUTED
FROM INFORMATION_SCHEMA.EVENTS
WHERE EVENT_SCHEMA = DATABASE();
サンプルクエリ
古いデータの削除
- 30日以上前のログデータを毎日削除するイベント
CREATE EVENT cleanup_old_logs ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 02:00:00' DO DELETE FROM logs WHERE created_date < NOW() - INTERVAL 30 DAY;
- 90日以上前のデータをバッチで削除し、負荷を分散する例
DELIMITER | CREATE EVENT batch_cleanup ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 03:00:00' DO BEGIN DECLARE i INT DEFAULT 0; WHILE i < 10 DO DELETE FROM transaction_logs WHERE created_date < NOW() - INTERVAL 90 DAY LIMIT 1000; SET i = i + 1; DO SLEEP(1); END WHILE; END | DELIMITER ;
集計テーブルの更新
- 1時間ごとにセンサデータを集計して、統計テーブルに挿入する例
DELIMITER | CREATE EVENT update_hourly_stats ON SCHEDULE EVERY 1 HOUR DO BEGIN INSERT INTO hourly_stats (stat_time, count, avg_value, max_value) SELECT CURRENT_TIMESTAMP, COUNT(*), AVG(value), MAX(value) FROM sensor_readings WHERE timestamp > CURRENT_TIMESTAMP - INTERVAL 1 HOUR; END | DELIMITER ;
- 毎日の売上集計を作成する例
DELIMITER | CREATE EVENT daily_sales_summary ON SCHEDULE EVERY 1 DAY STARTS '2026-01-01 23:00:00' DO BEGIN INSERT INTO daily_sales (sale_date, total_amount, order_count) SELECT CURDATE(), SUM(amount), COUNT(*) FROM orders WHERE DATE(order_date) = CURDATE(); END | DELIMITER ;
定期メンテナンス
- 毎週テーブルを最適化し、統計情報を更新するイベントを作成する。
DELIMITER | CREATE EVENT weekly_maintenance ON SCHEDULE EVERY 1 WEEK STARTS '2026-01-05 03:00:00' DO BEGIN OPTIMIZE TABLE users; OPTIMIZE TABLE transactions; OPTIMIZE TABLE logs; ANALYZE TABLE users; ANALYZE TABLE transactions; ANALYZE TABLE logs; END | DELIMITER ;
- 毎月1日にレポートを生成するイベントを作成する。
CREATE EVENT monthly_report_generation ON SCHEDULE EVERY 1 MONTH STARTS '2026-03-01 01:00:00' DO CALL generate_monthly_report();
CRONとの比較
下表に、イベントスケジューラとCRONの比較を示す。
| 項目 | イベントスケジューラ | cron |
|---|---|---|
| 実行環境 | MySQL内 | OS (UNIX系システム) |
| 設定場所 | データベース内 | crontabファイル |
| 実行内容 | SQL文、ストアドプロシージャ | シェルスクリプト、コマンド、プログラム |
| OS依存性 | 非依存 (移植性が高い) | 依存 (UNIX系のみ) |
| 権限管理 | DEFINER で一元管理 | ユーザ権限、ファイルシステム権限 |
| ログ確認 | INFORMATION_SCHEMA.EVENTS | syslog、cronログ |
| データベース停止時 | 実行されない | 実行可能 (データベース接続が必要) |
| 複雑な処理 | SQLの範囲内 | 任意のプログラム実行可能 |
| スケジューリング精度 | 秒単位 | 分単位 (標準) |
| エラーハンドリング | SQLエラーハンドリング | シェルスクリプトのエラー処理 |
| 方式 | メリット |
|---|---|
| イベントスケジューラ | SQL内で完結し、外部スクリプトが不要である |
| OS非依存で移植性が高い。 | |
| DEFINER権限で一元管理できる。 | |
INFORMATION_SCHEMA.EVENTS で実行情報を確認できる。
| |
| データベースと一体化しており、バックアップ時にイベント定義も含められる。 | |
| cron | シェルスクリプトや外部プログラムを実行できる。 |
| POSIX標準で多くのシステムで利用可能である。 | |
| データベース停止時も動作可能である。 | |
| より柔軟なスケジューリングが可能である。 | |
| システムレベルのタスクを実行できる。 |
用途に応じて、イベントスケジューラとCRONを使い分けることが推奨される。
データベース内部の定期処理にはイベントスケジューラを使用し、外部プログラムの実行やシステムレベルのタスクにはCRONを使用するとよい。
イベントスケジューラの制限事項
イベントスケジューラには、以下に示すような制限事項がある。
| 制限事項 | 説明 |
|---|---|
LOCK TABLES / UNLOCK TABLES は使用不可 |
イベント内でテーブルロックを明示的に取得・解放することはできない。 |
ALTER VIEW は使用不可 |
イベント内でビューの定義を変更することはできない。 |
LOAD DATA / LOAD XML は使用不可 |
イベント内で外部ファイルからデータをロードすることはできない。 |
| イベント内からのイベント操作は不可 | イベント内で CREATE EVENT、ALTER EVENT、DROP EVENT を実行することはできない。
|
| イベント名の大文字小文字は区別されない | event_name と EVENT_NAME は同一のイベントとして扱われる。 |
| 複数実行保護メカニズムがない | 同じイベントが前回の実行完了前に再度トリガーされる可能性がある。GET_LOCK() 関数で排他制御を実装する必要がある。
|
| 年2038以上の日付はサポートされない | 32ビット UNIXエポックの制限により、2038年1月19日以降の日付を正確に扱えない場合がある。 |
複数実行を防ぐための排他制御の例を以下に示す。
以下の例では、GET_LOCK() 関数でロックを取得して、ロック取得に成功した場合のみ処理を実行する。
GET_LOCK('my_event_lock', 0) の第2パラメータ 0は、タイムアウトを0秒に設定しており、即座にロック取得の成否を返す。
DELIMITER |
CREATE EVENT protected_event
ON SCHEDULE EVERY 5 MINUTE
DO BEGIN
DECLARE lock_acquired INT;
SET lock_acquired = GET_LOCK('my_event_lock', 0);
IF lock_acquired = 1 THEN
-- 実際の処理
DELETE FROM logs WHERE created_date < NOW() - INTERVAL 30 DAY;
DO RELEASE_LOCK('my_event_lock');
END IF;
END |
DELIMITER ;
関連ページ