「DB運用」タグアーカイブ

SQL:重複データを安全に削除する方法(DELETE+ROW_NUMBER)

データベースを長く運用していると、アプリのバグやテストデータの混入、複数サーバ間複製のトラブルなどが原因で、重複データが発生することがあります。
しかし、安易に DELETE を実行すると必要なデータまで消えてしまう危険があります。

そこで本記事では、ROW_NUMBER() を使って重複行を安全に削除する方法をわかりやすく解説します。


🎯 本記事のゴール

  • 重複データを判定する方法が理解できる

  • 削除対象を事前に確認できる

  • ROW_NUMBER()DELETE の実践手順がわかる


重複データとは?

以下のように、ユニークであるべき項目(メールアドレス、社員番号、商品コードなど)が複数存在する状態です。

idemailname
1aaa@test.com
Tanaka
2aaa@test.com
Tanaka
3bbb@test.com
Suzuki

この場合、aaa@test.com が重複行となります。


手順①:重複データの行番号を振る

まずは削除対象となる行を特定します。
ROW_NUMBER() OVER (PARTITION BY ...) で同じキーを持つ行に番号を付与します。

実行結果例

idemailrn
1aaa@test.com
1
2aaa@test.com
2
3bbb@test.com
1

rn = 1 を残して rn > 1 を削除対象とします。


手順②:削除対象のみを事前確認

※ 実務では必ずこのチェックを推奨


手順③:重複行を削除

🔒 サブクエリが必要な理由

一部DBでは DELETE ... FROM 内で ROW_NUMBER() を直接参照できないため
サブクエリ(派生テーブル)を挟む必要があります。


💡 Delete 実行前の注意点

注意点内容
バックアップ取得DELETE後は戻せない
トランザクション内で実行BEGIN / ROLLBACK の利用
WHERE句のチェックWHERE間違いは致命傷
ORDER BYの基準を決める新しいデータを残す/古いデータを残すなど

例:最新データを残したい場合


DBごとの対応表

DB使用可否
PostgreSQL
SQL Server
Oracle
MySQL 8.0 以降
MySQL 5.x× → サブクエリ+JOINで対応
MariaDB

※ MySQL 5系の場合は別途記事で解説予定


まとめ

結論内容
ROW_NUMBER()は重複削除に最適削除対象を明確化できる
いきなりDELETEしないSELECTで必ず事前確認
ORDER基準を明確にする残すデータのルール決め

安全に確実に重複を削除するには
「削除対象の可視化」→「確認」→「DELETE」
という流れがとても重要です。

MySQLで「Too many connections」エラーが出たときの原因と対処法

MySQLを運用していると、ある日突然アプリケーション側から「Too many connections」というエラーが返され、データベースに接続できなくなることがあります。これは利用者にとってはサイトやサービスが「停止状態」と同じであり、早急な対応が必要です。本記事では、このエラーの原因と具体的な対処方法を整理します。


「Too many connections」エラーとは?

MySQLには同時に接続できるクライアント数を制御する仕組みがあります。
max_connections というパラメータで上限値が決められており、この数を超える新規接続要求があった場合に 「Too many connections」 エラーが発生します。

  • 初期値:151(バージョンによって異なる)

  • 上限:OSやハードウェアのリソースに依存

つまり、データベースが過負荷状態になったサインと捉えることができます。


主な原因

1. 接続数の急増

一時的にアクセスが集中し、アプリケーションからの同時接続数が急増することで上限を超えてしまいます。

2. 接続のクローズ漏れ

アプリケーション側で 接続プールの管理不備close処理の抜け があると、不要な接続が残り続けます。

3. 長時間実行されるクエリ

重いSQLが大量に実行されると、処理待ちの接続が積み重なり、結果的に接続枠を圧迫します。

4. 不適切な設定

wait_timeoutinteractive_timeout の値が長すぎると、アイドル状態の接続が切断されずに残ってしまうことがあります。


対処法

1. 一時的な応急処置

まずはサービス復旧を優先します。
MySQLに管理者で接続できる場合、現在の接続状況を確認します。

SHOW PROCESSLIST;
不要な接続が溜まっている場合は、強制的に切断します。
 
KILL 接続ID;

どうしても管理者で接続できない場合は、MySQLサービスの再起動が必要になる場合もあります。
(※ただし根本解決にはならず、緊急回避策に過ぎません。)


2. 根本的な解決策

(1) max_connections を増やす

一時的なアクセス増に備えるために上限値を上げます。

SET GLOBAL max_connections = 300;
永続化する場合は my.cnf に設定を追記します。
 
[mysqld]
max_connections = 300

(2) 接続プールの導入・見直し

アプリケーションで コネクションプーリング を利用し、使い終わった接続は必ず解放するようにします。
JavaならHikariCP、PHPならPDOやmysqliの接続プールを利用するのが一般的です。

(3) クエリのチューニング

  • インデックスを適切に設定する

  • 不要なJOINやサブクエリを減らす

  • キャッシュを導入する

これにより接続が長時間占有されることを防ぎます。

(4) timeout の調整

不要な接続が残り続けないように、wait_timeout の値を短めに設定します。

[mysqld]
wait_timeout = 60
interactive_timeout = 60

再発防止のために

  • アクセスのピーク時を想定して性能テストを行う

  • アプリケーション側で接続管理を徹底する

  • 監視ツール(例:Zabbix, Prometheus, CloudWatchなど)で接続数を常時モニタリングする

これらを実施することで「Too many connections」エラーを未然に防ぐことができます。


まとめ

「Too many connections」エラーは単なる設定値不足ではなく、接続管理やクエリ設計の問題 が隠れていることが多いです。

  • 一時的には接続数の上限を増やす

  • 長期的にはアプリケーション側の接続管理やSQLチューニングを見直す

これらをバランスよく行うことで、安定したMySQL運用が可能になります。