背景
現場の開発や運用環境で、MySQL の ONLY_FULL_GROUP_BY の設定に関する問題が生じた経験から、本記事では「ONLY_FULL_GROUP_BY とは何か」「無効化する手順」「注意点」を中心に解説します。また、「ONLY_FULL_GROUP_BY の無効化」が実際のプロジェクトでどのような背景や影響を持つのかについても触れます。
ONLY_FULL_GROUP_BY とは
概要
ONLY_FULL_GROUP_BY は、MySQL の SQL モードの一つで、GROUP BY句を使ったクエリにおいて、非集約カラムの取り扱いを厳密に制御するための設定です。このモードが有効になっている場合、GROUP BY 句で指定されていないカラムは、SQLクエリのSELECTリストに記述できません。
なぜ ONLY_FULL_GROUP_BY が必要か
SQL の標準仕様では、GROUP BY 句を使う場合、集約関数(例: SUM() や COUNT())以外のカラムをSELECTで取り扱うことはできません。このルールを緩くすると、結果が曖昧になりやすく、予期しない動作を引き起こす可能性があります。ONLY_FULL_GROUP_BY を有効化することで、SQL の標準的なルールを強制し、クエリの安全性や可読性を高めることができます。
有効な場合と無効な場合の違い
ONLY_FULL_GROUP_BY が有効な場合
以下のクエリはエラーになります(MySQL は非集約カラムの扱いを許可しない)。
SELECT name, COUNT(*)
FROM users
GROUP BY department_id;
理由: name が GROUP BY に含まれていないため。
修正後の正しいクエリ例:
SELECT department_id, COUNT(*)
FROM users
GROUP BY department_id;
ONLY_FULL_GROUP_BY が無効な場合
無効にした場合、以下のような曖昧なクエリが許可されます。
SELECT name, COUNT(*)
FROM users
GROUP BY department_id;
この場合、name の値はMySQLが内部的に適当に1つ選択します(予測不能な挙動)。
実装手順: ONLY_FULL_GROUP_BY を無効化する方法
以下の手順で ONLY_FULL_GROUP_BY を無効化できます。
1. 現在の sql_mode を確認
まず、MySQL サーバーの現在の sql_mode を確認します。
SELECT @@sql_mode;
結果例:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
この場合、ONLY_FULL_GROUP_BY が有効になっていることが分かります。
2. 一時的に無効化する(セッション単位で設定)
現在のセッションに限定して ONLY_FULL_GROUP_BY を無効化するには、以下のSQLコマンドを実行します。
SQL コマンド:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
ポイント:
この設定は現在のセッションのみで有効です。他の接続や再起動後には元に戻ります。
3. 永続的に無効化する(グローバル設定)
MySQL サーバー全体で ONLY_FULL_GROUP_BY を無効化するには、以下のコマンドを使用します。
SQL コマンド:
``
SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
ポイント:
すべての新しいセッションに適用されます。
サーバー再起動後には設定がリセットされる可能性があります(my.cnfで設定が必要)。
### 4. 永続化(my.cnf を編集)
サーバー再起動後も設定を保持したい場合は、MySQL の設定ファイル (my.cnf または my.ini) に変更を加える必要があります。
手順:
my.cnf または my.ini を開きます。
以下のように sql_mode を設定します。
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
MySQL サーバーを再起動します。
sudo systemctl restart mysql
まとめ
メリットとデメリット
無効化のメリット:
古いコードや曖昧なクエリでも動作する。
アプリケーションを修正するコストが抑えられる。
無効化のデメリット:
SQL の標準仕様から外れる。
クエリの動作が予測不能になりやすい。
将来のメンテナンスや移行時に問題が発生する可能性がある。
再検討: 本当に無効化すべきか?
現場で ONLY_FULL_GROUP_BY を無効化するのは、過去の設計に問題があり、修正が困難な場合が多いです。しかし、可能であればクエリをリファクタリングし、標準仕様に適合させることが推奨されます。
次のステップ
開発環境で設定変更を試し、影響範囲を確認する。
長期的にはクエリをリファクタリングして、ONLY_FULL_GROUP_BY を有効化できる状態にする。
これで、ONLY_FULL_GROUP_BY の無効化について正しく理解し、適切に対応できるはずです。