DELETE、TRUNCATE、DROP: 違い、ロールバック、それぞれを使用する場合
3 つのコマンドはすべて何かを削除しますが、異なるものを異なる方法で削除します。ここでは、それぞれの機能、取り消しできる内容、データベース間でルールがどのように変化するかを示します。
- DELETE は行を削除します。必要に応じて WHERE でフィルタリングします。テーブルはそのままです。
- TRUNCATE はすべての行をすばやく削除します。テーブル構造はそのまま残ります。
- DROP はテーブル全体 (データ、構造、インデックス、トリガー) を削除します。
- ロールバック、トリガー、ID リセットの動作はデータベースごとに異なるため、データベースを確認してください。
テスターは、新たなテストを実行する前にステージング テーブルをクリアしたいと考えています。 DELETE、TRUNCATE、DROPのどれにするべきですか?選択を誤ると、ジョブが遅くなったり、テーブルが欠落したり、本番環境では非常に悪い午後になったりする可能性があります。
以下の DELETE および DROP の例を SQLite 3.50 で実行し、出力はその実行から得られます。 SQLite には TRUNCATE コマンドがないため、TRUNCATE のメモは独自のテストではなく、PostgreSQL、MySQL、および SQL Server の公式ドキュメントに基づいています。
短い答え
- いくつか行を削除する必要がありますか?
DELETE ... WHEREを使用します。 - テーブルを空にしたままにしておく必要がありますか?サポートされている場合は
TRUNCATEを使用してください。 - テーブルを完全になくす必要がありますか?
DROP TABLEを使用します。
DELETE: 行を削除します
DELETE はデータ変更 (DML) コマンドです。一度に 1 行ずつ削除し、行レベルのトリガーを起動し、フィルター処理することができます。監査トリガーを備えた小さなテーブルを設定します。
CREATE TABLE logs (id INTEGER PRIMARY KEY AUTOINCREMENT, level TEXT);
INSERT INTO logs (level) VALUES ('INFO'),('ERROR'),('INFO'),('DEBUG');
CREATE TABLE audit (msg TEXT);
CREATE TRIGGER logs_delete AFTER DELETE ON logs
BEGIN INSERT INTO audit VALUES ('deleted ' || OLD.id); END;
DELETE FROM logs WHERE level = 'DEBUG';
SELECT id, level FROM logs; -- (1,'INFO'), (2,'ERROR'), (3,'INFO')
SELECT * FROM audit; -- 'deleted 4'
一致する行のみが実行され、トリガーがそれを記録しました。 WHERE 句を指定せずに DELETE FROM logs を実行すると、他の 3 行が削除され、監査テーブルには、削除された行ごとに 1 つずつ、合計 4 つのエントリが保持されました。
DELETE は自動インクリメントカウンターをリセットしません。テーブルを空にした後、次の挿入は 1 ではなく id 5 を受け取りました。SQLite では、これは AUTOINCREMENT が原因です。 MySQL InnoDB および SQL Server の ID 列も、DELETE 後の位置から続行されます。
ヒント: WHERE 句を使用した DELETE の前に、SELECT COUNT(*) と同じ句を最初に実行します。カウントに驚いたら、やめてください。 WHERE 句で NULL が作成するトラップについては、SQL NULL 値に関するガイドをお読みください。
TRUNCATE: テーブルを空にします
TRUNCATE TABLE logs; はすべての行を一度に削除します。 WHERE 句を使用することはできません。通常、データベースは行を 1 つずつ削除するのではなく、テーブルのデータ ページを解放します。そのため、大規模なテーブルでは処理がはるかに高速になります。
SQLite で実行すると、SQLite には次のコマンドがないため、構文エラーが発生しました。
TRUNCATE TABLE logs;
-- near "TRUNCATE": syntax error
SQLite では、WHERE 句なしで DELETE FROM logs; を使用します。 SQLite のドキュメントには、テーブルにトリガーがない場合にこれを高速化する「切り捨て最適化」について説明されています。このテーブルにはトリガーがあったため、削除は行ごとに実行され、行ごとに実行されました。
TRUNCATE をサポートするデータベースでは、ドキュメントによると次のようになります。
- 通常はそうなりますそうではない行レベルの DELETE トリガーを起動します。
- 通常、MySQL や SQL Server などの ID または自動インクリメント カウンターがリセットされます。 PostgreSQL では
RESTART IDENTITYを追加します。 - ほとんどのシステムでは、DELETE よりも強力な権限が必要です。
DROP: テーブル自体を削除します
DROP TABLE はスキーマ (DDL) コマンドです。データ、テーブル定義、そのインデックス、トリガー、制約が削除されます。ビューや外部キーなど、テーブルを参照するものすべても影響を受けます。
DROP TABLE logs;
SELECT * FROM logs;
-- no such table: logs
DROP TABLE IF EXISTS logs; -- no error, even though it is gone
IF EXISTS は、複数回実行されるセットアップ スクリプトで便利です。 SQL ビューの説明 で示したように、ドロップされたテーブルのビューは壊れる可能性があります。
比較表
| 特徴 | 削除 | 切り詰める | ドロップ |
|---|---|---|---|
| 削除します | 一部またはすべての行 | すべての行 | テーブルと行 |
| WHERE句 | はい | いいえ | いいえ |
| コマンドの種類 | DML | DDL (通常) | DDL |
| 行トリガーが発火する | はい | 通常はありません | いいえ |
| アイデンティティをリセットします | いいえ | 通常ははい | テーブルがなくなった |
| 大きなテーブルでのスピード | 遅い | 速い | 速い |
| テーブル残り | はい | はい | いいえ |
ロールバックできますか?
多くの記事が過度に単純化しているのはこの点です。正直な答えは、それはデータベースに依存するということです。
DELETE はトランザクション内であればどこでもロールバックできます。私たちはそれをテストしました:
BEGIN;
DELETE FROM logs;
SELECT COUNT(*) FROM logs; -- 0
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 3
DROP も、トランザクション DDL をサポートする SQLite でロールバックされました。
BEGIN;
DROP TABLE logs;
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 1 (the table is back)
他のデータベースの TRUNCATE と DROP については、ドキュメントによると次のようになります。
| データベース | トランザクションでの TRUNCATE / DROP |
|---|---|
| PostgreSQL | ロールバック可能。 DDL はトランザクションです。 |
| SQLサーバー | 明示的なトランザクション内でロールバックできます。 |
| MySQL | 暗黙的なコミットが発生するため、ロールバックできません。 |
| オラクル | 暗黙的にコミットします。 DROP はごみ箱から回復できる場合があります。 |
したがって、「TRUNCATE は決してロールバックできない」は PostgreSQL と SQL Server では誤りであり、「いつでもロールバックできる」は MySQL では誤りです。トランザクション外では、バックアップがなければそれらを元に戻すことはできません。
TRUNCATE が速い理由
DELETE は、削除された各行をログに記録して、変更を元に戻して複製できるようにし、トリガーを起動して行ごとに制約をチェックします。数百万行のテーブルでは、大量の作業とログの量が発生します。 TRUNCATE は通常、1 回の操作でストレージの割り当てを解除し、ログの量を大幅に減らします。すべてではなく大きなサブセットを削除するには、長時間のロックを避けるためにバッチで削除します。ロックとクエリのコストについては、SQL クエリの最適化 で説明します。
外部キーと権限
- 外部キー。 SQL Server は、外部キーによって参照されるテーブルの TRUNCATE を拒否します。 PostgreSQL では、参照テーブルも切り詰めるか、
CASCADEを使用する必要があります。 DELETE では、代わりに制約に対して各行をチェックします。 - 権限。 DELETE には削除権限が必要です。多くの場合、TRUNCATE には ALTER または専用の TRUNCATE 権限が必要で、DROP にはスキーマに対する所有権または ALTER が必要です。
- レプリケーションと監査。 他のシステムが行レベルの変更ログまたはトリガーに依存している場合、TRUNCATE はそれらをスキップする可能性があります。まずはそれらのシステムの所有者に問い合わせてください。
どれを使うか
| 状況 | 使用する |
|---|---|
| 顧客のキャンセルされた注文を削除する | WHERE で削除 |
| 各テストの実行前にステージング テーブルをリセットする | TRUNCATE (SQLite では DELETE) |
| 監査トリガーを機能させ続ける | 削除 |
| デザインに含まれなくなったテーブルを削除する | レビューされた移行での DROP |
| 何百万もの古い行を削除しますが、最近の行は保持します | バッチで削除するか、古いパーティションを分割して削除します |
テスト データの場合、ID をリセットしてテストを反復可能にする TRUNCATE が一般的です。ロールバックされるトランザクションで各テストをラップすることも別のオプションであり、SQL トランザクションと ACID で説明されています。
安全チェックリスト
- 接続しているデータベースと環境を確認してください。
- 最初に WHERE 句を SELECT として実行します。
- データベースがサポートしているトランザクション内で変更をラップします。
- 運用環境で TRUNCATE または DROP を実行する前に、テスト済みの最新のバックアップを作成してください。
- DROP ステートメントは、アドホック コンソールではなく、レビュー済みの移行スクリプトに含めてください。
- テーブルを削除する前に、ビュー、外部キー、レポートなど、テーブルに依存するものを確認してください。
大量のデータを安全に削除する
1 回の DELETE で数百万行を削除すると、テーブルが長時間ロックされ、トランザクション ログがいっぱいになり、レプリケーションが遅くなる可能性があります。一般的なパターンは、小さなバッチで削除し、何も残らなくなるまで繰り返すことです。
-- SQL Server style (not run for this article)
DELETE TOP (5000) FROM logs WHERE created_at < '2026-01-01';
-- PostgreSQL style (not run for this article)
DELETE FROM logs
WHERE id IN (SELECT id FROM logs WHERE created_at < '2026-01-01' LIMIT 5000);
ゼロ行が報告されるまで、バッチ間に短い一時停止を挟みながら、ステートメントをループで実行します。各バッチは小さなトランザクションであるため、ロックは短く、他のクエリは実行され続けます。フィルター列のインデックス (ここでは created_at) により、すべてのバッチが高速に保たれます。
ログやイベントなど、日付ごとに増加するデータの場合は、テーブル パーティショニング の方がさらに優れています。各月は独自のパーティションに存在し、古いデータの削除は、行を 1 つずつ削除するのではなく、1 つのパーティションを削除または切り捨てる簡単な操作になります。
論理的な削除
多くのアプリケーションはビジネス レコードを物理的に削除しません。 deleted_at などの列を追加して代わりに設定し、クエリを deleted_at IS NULL でフィルター処理します。論理的な削除により回復が容易になり、監査用に履歴が保存されますが、すべてのクエリでフィルターを記憶する必要があり、これは ビュー にとって適切な仕事です。論理的に削除された行にはその値がまだ保持されているため、一意の制約にも注意が必要です。プライバシー法では、一定期間後に個人データを実際に削除することが求められる場合があるため、論理的な削除は保持ポリシーの代わりにはなりません。
まとめ
DELETE は正確かつ慎重なツールです。 TRUNCATE は高速リセット ボタンで、DROP はテーブルを完全に削除します。最大のリスクは、特にロールバックに関して、あるデータベースが別のデータベースと同じように動作すると想定することです。疑問がある場合は、まず独自のデータベース内のテーブルのコピーでコマンドをテストしてください。
よくある質問
DELETE と TRUNCATE の主な違いは何ですか?
DELETE は行を 1 つずつ削除し、WHERE をサポートし、トリガーを起動します。 TRUNCATE はすべての行を一度に削除し、はるかに高速で、通常は行トリガーをスキップし、多くの場合 ID カウンターをリセットします。
TRUNCATEはロールバックできますか?
PostgreSQL と SQL Server では、はい、トランザクション内です。 MySQL と Oracle では暗黙的にコミットされるため、ロールバックできません。
DELETE は自動インクリメント値をリセットしますか?
いいえ。DELETE の後、新しい行は前のカウンターから継続されます。 SQLite テストでは、すべての行を削除した後の次の ID は 5 でした。
SQLite は TRUNCATE をサポートしていますか?
いいえ。WHERE 句のない DELETE FROM テーブルを使用してください。 SQLite は、テーブルにトリガーがない場合にこれを最適化します。
DROP TABLE は何を削除しますか?
データ、テーブル定義、インデックス、トリガー、制約。テーブルに依存するビューと外部キーは、ドロップを中断またはブロックする可能性があります。
学び続ける
テスト、WordPress、または SEO についてサポートが必要ですか?
私たちは、チームがより優れたソフトウェアを出荷し、サイトを成長させるのを支援します。あなたが取り組んでいることを教えてください。明確な次のステップを提案します。
詳しいガイドはこちら テスト、AI、最新の開発
この記事は気に入りましたか?トピックを選択して、最新のチュートリアルに直接アクセスしてください。
AI 幻覚の説明: 言語モデルが物事をでっち上げる理由とそれを軽減する方法
AI 幻覚について説明しました。幻覚とは何か、言語モデルが幻覚を生成する理由、一般的な種類、グラウンディングとプロンプトで幻覚を軽減する方法、そして私たちが実行した簡単なチェックです。
記事を読む →DevOps環境変数の説明: .env ファイル、シークレット、および設定が正しく行われている
実行した Python の例を使用して環境変数について説明します。環境変数の読み取りと設定、すべての値が文字列である理由、.env ファイル、プロセスの継承、シークレット、検証について説明します。
記事を読む →ソフトウェア開発API レート制限の説明: アルゴリズム、ヘッダー、および 429 エラーの処理
API レート制限については、実行したシミュレーションで説明します。トークン バケット、固定ウィンドウ、スライディング ウィンドウ、429 応答、レート制限ヘッダー、バックオフによる再試行、およびテスト制限です。
記事を読む →テスト自動化Python でのモッキング:unittest.mock、patch、およびテストを嘘にする間違い
Python でのunittest.mockによるモック、テスト済み: モックとreturn_value、side_effect、名前が使用されている場所のパッチ、仕様と自動仕様、日付のモック、およびよくある間違い。
記事を読む →ソフトウェアテストコードカバレッジの説明: 回線カバレッジとブランチカバレッジ、および 100% の実際の意味
実際のcoverage.pyの実行でコードカバレッジを説明: 行、分岐、条件のカバレッジ、レポートの読み取り、100%のカバレッジでもバグを見逃す可能性がある理由、および賢明なターゲット。
記事を読む →データベースとSQLSQL における DELETE、TRUNCATE、DROP: 違い、ロールバック、およびそれぞれをいつ使用するか
DELETE、TRUNCATE、DROP について、テスト済み SQL を使用して説明します。それぞれの削除内容、ロールバック、トリガー、ID リセット、速度、PostgreSQL、MySQL、SQL Server、SQLite の違いについて説明します。
記事を読む →データベースとSQLSQL ビューの説明: 作成、使用、落とし穴の回避、例を示します
SQL ビューについて、実行したクエリとともに説明しました。ビューの作成、ライブ結果、列の非表示、パフォーマンス、更新可能なビューと具体化されたビュー、壊れた依存関係、ベスト プラクティスについて説明します。
記事を読む →ソフトウェア開発TypeScript インターフェイスと型: 実際の違い、コンパイラでテスト
TypeScript インターフェイスと型、実際のコンパイラでチェック: 両方でできること、片方だけでできること、宣言のマージ、拡張と交差、および従うべき簡単なルール。
記事を読む →ソフトウェア開発Python *args と **kwargs の説明: 柔軟な関数と明確な例
Python の *args と **kwargs について、実行したコードで説明しました。パッキングとアンパッキング、パラメーターの順序、キーワードのみの引数と位置のみの引数、デコレーター、一般的なエラーです。
記事を読む →ソフトウェア開発Python Lambda 関数: 構文、実際の用途、および使用すべきでない場合
Python のラムダ関数について、実行したコードとともに説明します。構文、キーによるソート、マップとフィルター、クロージャー、遅延バインディング トラップ、通常の def がより適切な選択である場合。
記事を読む →人工知能AIエージェントとは何ですか?シンプルなエージェント ループを実行できる仕組み
AIエージェントとは何ですか?エージェント ループ、ツール、メモリ、ガードレール、実行した小さな Python ループ、実際のリスク、およびシンプルなチャットボットがより良い選択である場合についてのわかりやすいガイドです。
記事を読む →DevOpsモニタリングと可観測性: ログ、メトリクス、トレースによる本当の違い
モニタリングと可観測性について説明: 既知および未知の障害、ログ、メトリクスとトレース、チェックアウト インシデントのウォークスルー、ゴールデン シグナル、OpenTelemetry、および便利なアラート。
記事を読む →DevOpsDocker ボリュームとバインド マウント: コンテナ データを正しい方法で保持する
Docker ボリュームとバインド マウントについて説明します。コンテナ データが消える理由、名前付きボリューム、バインド マウント、tmpfs、Compose の例、バックアップ、アクセス許可、およびそれぞれをいつ使用するかについて説明します。
記事を読む →テスト自動化TDD と BDD: 主な違い、1 つの機能が両方の方法で構築され、それぞれをいつ使用するか
TDD と BDD は、両方の方法で構築された 1 つの割引機能で説明されています。実行したコードによるレッド-グリーン-リファクタリング、Given-When-Then シナリオ、ツール、トレードオフ、およびそれぞれをいつ使用するかです。
記事を読む →ソフトウェア開発Git mergeとrebaseの違い:例と使い分け
Git mergeとrebaseの違いを、実際のログ出力、比較表、rebaseの黄金律、安全なチームワークフローで解説します。
記事を読む →ソフトウェア開発Pythonのリスト内包表記:構文・例・使うべきでない場面
Pythonのリスト内包表記を解説:構文、フィルタ、if-else、ネストしたループ、実測した処理時間、そして通常のforループの方が良い場面。
記事を読む →データベースとSQLSQL JOINを例で解説(Inner・Left・Right・Full)
サンプルのテーブルとクエリでSQL JOINを順に解説。INNER、LEFT、RIGHT、FULL、CROSS、SELFに加え、よくある間違いとパフォーマンスのコツも紹介します。
記事を読む →