DELETE vs TRUNCATE vs DROP: Różnice, wycofywanie i kiedy używać każdego z nich
Wszystkie trzy polecenia usuwają coś, ale usuwają różne rzeczy na różne sposoby. Oto, co robi każdy z nich, co można cofnąć i jak zmieniają się reguły między bazami danych.
- DELETE usuwa wiersze, opcjonalnie przefiltrowane za pomocą WHERE. Stół zostaje.
- TRUNCATE szybko usuwa wszystkie wiersze. Struktura tabeli pozostaje.
- DROP usuwa całą tabelę: dane, strukturę, indeksy i wyzwalacze.
- Wycofywanie zmian, wyzwalacze i resetowanie tożsamości zachowują się inaczej w każdej bazie danych, więc sprawdź swoją.
Tester chce wyczyścić tabelę pomostową przed ponownym uruchomieniem testu. Czy powinno być DELETE, TRUNCATE czy DROP? Zły wybór może oznaczać powolną pracę, brak stołu lub bardzo złe popołudnie na produkcji.
Poniższe przykłady DELETE i DROP uruchomiliśmy w SQLite 3.50, a dane wyjściowe pochodzą z tego uruchomienia. W SQLite nie ma polecenia TRUNCATE, więc uwagi TRUNCATE opierają się na oficjalnej dokumentacji PostgreSQL, MySQL i SQL Server, a nie na naszym własnym teście.
Krótka odpowiedź
- Chcesz usunąć niektóre wiersze? Użyj
DELETE ... WHERE. - Chcesz opróżnić stół, ale go zatrzymać? Użyj
TRUNCATE, jeśli jest to obsługiwane. - Chcesz, żeby stół zniknął na dobre? Użyj
DROP TABLE.
DELETE: usuń wiersze
DELETE to polecenie zmiany danych (DML). Usuwa wiersze pojedynczo, uruchamia wyzwalacze na poziomie wiersza i można je filtrować. Przygotowaliśmy małą tabelę z wyzwalaczem audytu:
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'
Poszedł tylko pasujący wiersz i wyzwalacz to zarejestrował. Uruchomienie DELETE FROM logs bez klauzuli WHERE spowodowało usunięcie pozostałych trzech wierszy, a tabela kontroli zawierała wówczas cztery wpisy, po jednym na każdy usunięty wiersz.
DELETE nie resetuje liczników automatycznego przyrostu. Po opróżnieniu tabeli nasza następna wstawka otrzymała id 5, a nie 1. W SQLite jest to spowodowane AUTOINCREMENT. Kolumny tożsamości MySQL InnoDB i SQL Server również kontynuują pracę od miejsca, w którym znajdowały się po wykonaniu DELETE.
Wskazówka: Przed jakimkolwiek DELETE z klauzulą WHERE, uruchom najpierw tę samą klauzulę co SELECT COUNT(*). Jeśli liczba cię zaskoczy, przestań. Przeczytaj nasz przewodnik po wartościach SQL NULL, aby dowiedzieć się, jakie pułapki tworzy NULL w klauzuli WHERE.
TRUNCATE: opróżnij tabelę
TRUNCATE TABLE logs; usuwa każdy wiersz na raz. Nie może przyjmować klauzuli WHERE. Zamiast usuwać wiersze jeden po drugim, baza danych zazwyczaj zwalnia strony danych tabeli, dlatego w przypadku dużych tabel działa znacznie szybciej.
Kiedy uruchomiliśmy go w SQLite, otrzymaliśmy błąd składniowy, ponieważ SQLite nie ma polecenia:
TRUNCATE TABLE logs;
-- near "TRUNCATE": syntax error
W SQLite użyj DELETE FROM logs; bez klauzuli WHERE. Dokumentacja SQLite opisuje „optymalizację obcięcia”, która sprawia, że jest to szybkie, gdy tabela nie ma wyzwalaczy. Nasza tabela miała wyzwalacz, więc usuwanie odbywało się wiersz po wierszu i uruchamiało go dla każdego wiersza.
W bazach danych obsługujących TRUNCATE, według ich dokumentacji:
- Zwykle nie uruchamia wyzwalacze DELETE na poziomie wiersza.
- Zwykle resetuje liczniki tożsamości lub automatycznego przyrostu, na przykład w MySQL i SQL Server. W PostgreSQL dodajesz
RESTART IDENTITY. - W większości systemów potrzebuje silniejszych uprawnień niż DELETE.
DROP: usuń sam stół
DROP TABLE to polecenie schematu (DDL). Usuwa dane, definicję tabeli, jej indeksy, wyzwalacze i ograniczenia. Ma to również wpływ na wszystko, co odnosi się do tabeli, na przykład widoki lub klucze obce.
DROP TABLE logs;
SELECT * FROM logs;
-- no such table: logs
DROP TABLE IF EXISTS logs; -- no error, even though it is gone
IF EXISTS jest przydatny w skryptach instalacyjnych, które mogą być uruchamiane więcej niż raz. Widoki opuszczonej tabeli mogą się zepsuć, jak pokazaliśmy w wyjaśnieniu widoków SQL.
Tabela porównawcza
| Funkcja | USUŃ | SKRÓĆ | UPUŚĆ |
|---|---|---|---|
| Usuwa | Niektóre lub wszystkie wiersze | Wszystkie rzędy | Tabela i wiersze |
| Klauzula WHERE | Tak | Nie | Nie |
| Typ polecenia | DML | DDL (zwykle) | DDL |
| Rząd wywołuje ogień | Tak | Zwykle nie | Nie |
| Resetuje tożsamość | Nie | Zwykle tak | Stół zniknął |
| Szybkość na dużych stołach | Powolny | Szybko | Szybko |
| Pozostaje stół | Tak | Tak | Nie |
Czy możesz się wycofać?
W tym miejscu wiele artykułów nadmiernie upraszcza. Szczera odpowiedź jest taka, że to zależy od bazy danych.
DELETE można wycofać w ramach transakcji w dowolnym miejscu. Przetestowaliśmy to:
BEGIN;
DELETE FROM logs;
SELECT COUNT(*) FROM logs; -- 0
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 3
DROP również wycofano w SQLite, który obsługuje transakcyjny DDL:
BEGIN;
DROP TABLE logs;
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 1 (the table is back)
Dla TRUNCATE i DROP w innych bazach danych, zgodnie z ich dokumentacją:
| Baza danych | TRUNCATE / DROP w transakcji |
|---|---|
| PostgreSQL | Można zwinąć. DDL jest transakcyjny. |
| Serwer SQL | Można wycofać w ramach jawnej transakcji. |
| MySQL’a | Powoduje niejawne zatwierdzenie, więc nie można go wycofać. |
| Wyrocznia | Zatwierdza niejawnie. DROP można odzyskać z kosza. |
Zatem „TRUNCATE nigdy nie można wycofać” jest błędne w przypadku PostgreSQL i SQL Server, a „zawsze można go wycofać” jest błędne w przypadku MySQL. Poza transakcją żadnej z nich nie można cofnąć bez kopii zapasowej.
Dlaczego TRUNCATE jest szybki
DELETE rejestruje każdy usunięty wiersz, aby można było cofnąć i powtórzyć zmianę, uruchamia wyzwalacze i sprawdza ograniczenia wiersz po wierszu. Na stole z milionami wierszy powoduje to dużo pracy i objętości dziennika. TRUNCATE zazwyczaj zwalnia pamięć w jednej operacji, rejestrując znacznie mniej. Aby usunąć duży podzbiór, a nie wszystko, usuwaj partiami, aby uniknąć długich blokad. Pokrywamy koszty blokowania i zapytań w ramach optymalizacji zapytań SQL.
Klucze obce i uprawnienia
- Klucze obce. SQL Server odmawia CIĘCIA tabeli, do której odwołuje się klucz obcy. PostgreSQL wymaga również obcięcia tabel referencyjnych lub użycia
CASCADE. Zamiast tego polecenie DELETE sprawdza każdy wiersz pod kątem ograniczeń. - Uprawnienia. DELETE wymaga uprawnień do usuwania. TRUNCATE często wymaga ALTER lub dedykowanego prawa TRUNCATE, a DROP wymaga własności lub ALTER w schemacie.
- Replikacja i audyt. Jeśli inne systemy zależą od dzienników zmian lub wyzwalaczy na poziomie wiersza, TRUNCATE może je pominąć. Najpierw skontaktuj się z właścicielem tych systemów.
Którego użyć
| Sytuacja | Użyj |
|---|---|
| Usuń anulowane zamówienia klienta | USUŃ za pomocą WHERE |
| Zresetuj tabelę pomostową przed każdym uruchomieniem testu | TRUNCATE (lub USUŃ w SQLite) |
| Utrzymuj działanie wyzwalaczy audytu | USUŃ |
| Usuń tabelę, której nie ma już w projekcie | DROP w sprawdzonej migracji |
| Usuń miliony starych wierszy, ale zachowaj najnowsze | USUŃ partiami lub podziel i usuń stare partycje |
W przypadku danych testowych popularny jest TRUNCATE, ponieważ resetuje identyfikatory, dzięki czemu testy są powtarzalne. Zawijanie każdego testu w wycofywaną transakcję to kolejna opcja wyjaśniona w Transakcje SQL i ACID.
Lista kontrolna bezpieczeństwa
- Sprawdź, z jaką bazą danych i środowiskiem jesteś połączony.
- Najpierw uruchom klauzulę WHERE jako SELECT.
- Zawiń zmianę w transakcji tam, gdzie obsługuje ją Twoja baza danych.
- Utwórz najnowszą, przetestowaną kopię zapasową przed TRUNCATE lub DROP w środowisku produkcyjnym.
- Umieść instrukcje DROP w sprawdzonych skryptach migracji, nigdy w konsolach ad hoc.
- Sprawdź, co zależy od tabeli, np. widoki, klucze obce i raporty, zanim ją upuścisz.
Bezpieczne usuwanie dużych ilości danych
Usunięcie milionów wierszy jednym DELETE może zablokować tabelę na długi czas, zapełnić dziennik transakcji i spowolnić replikację. Powszechnym wzorcem jest usuwanie w małych partiach i powtarzanie, aż nic nie pozostanie:
-- 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);
Uruchom instrukcję w pętli, z krótką przerwą między partiami, aż zgłosi zero wierszy. Każda partia to mała transakcja, więc blokady są krótkie, a inne zapytania nadal działają. Indeks w kolumnie filtra, tutaj created_at, zapewnia szybkość każdej partii.
W przypadku danych rosnących według daty, takich jak dzienniki i zdarzenia, partycjonowanie tabeli jest jeszcze lepsze. Każdy miesiąc znajduje się na osobnej partycji, a usuwanie starych danych staje się szybką operacją, która powoduje usunięcie lub obcięcie jednej partycji zamiast usuwania wierszy jeden po drugim.
Miękkie usuwa
Wiele aplikacji nigdy fizycznie nie usuwa rekordów biznesowych. Dodają kolumnę taką jak deleted_at i zamiast tego ustawiają ją, a następnie zapytania filtrują według deleted_at IS NULL. Miękkie usunięcia ułatwiają odzyskiwanie i przechowują historię na potrzeby audytów, ale każde zapytanie musi pamiętać filtr, co jest dobrym zadaniem w przypadku widoku. Unikalne ograniczenia również wymagają ostrożności, ponieważ nietrwale usunięty wiersz nadal zachowuje swoją wartość. Przepisy dotyczące prywatności mogą wymagać rzeczywistego usunięcia danych osobowych po pewnym czasie, więc trwałe usunięcie nie zastępuje polityki przechowywania.
Podsumowanie
DELETE to precyzyjne i ostrożne narzędzie. TRUNCATE to przycisk szybkiego resetowania, a DROP całkowicie usuwa tabelę. Największym ryzykiem jest założenie, że jedna baza danych zachowuje się jak inna, szczególnie w przypadku wycofywania zmian. W razie wątpliwości przetestuj najpierw polecenie na kopii tabeli we własnej bazie danych.
Najczęstsze pytania
Jaka jest główna różnica między DELETE i TRUNCATE?
DELETE usuwa wiersze jeden po drugim, obsługuje WHERE i uruchamia wyzwalacze. TRUNCATE usuwa wszystkie wiersze na raz, jest znacznie szybszy, zwykle pomija wyzwalacze wierszy i często resetuje liczniki tożsamości.
Czy TRUNCATE można wycofać?
W PostgreSQL i SQL Server tak, w ramach transakcji. W MySQL i Oracle zatwierdza to niejawnie, więc nie można go wycofać.
Czy DELETE resetuje wartość automatycznego zwiększania?
Nie. Po wykonaniu DELETE nowe wiersze będą kontynuowane od poprzedniego licznika. W naszym teście SQLite następnym identyfikatorem było 5 po usunięciu wszystkich wierszy.
Czy SQLite obsługuje TRUNCATE?
Nie. Użyj tabeli DELETE FROM bez klauzuli WHERE. SQLite optymalizuje to, gdy tabela nie ma wyzwalaczy.
Co usuwa DROP TABLE?
Dane, definicja tabeli, indeksy, wyzwalacze i ograniczenia. Widoki i klucze obce zależne od tabeli mogą przerwać lub zablokować upuszczenie.
Ucz się dalej
Potrzebujesz pomocy przy testowaniu, WordPressie lub SEO?
Pomagamy zespołom dostarczać lepsze oprogramowanie i rozwijać ich witryny. Powiedz nam, nad czym pracujesz, a my zaproponujemy jasny następny krok.
Więcej poradników na testowanie, sztuczna inteligencja i nowoczesny rozwój
Podobał Ci się ten artykuł? Wybierz temat i przejdź bezpośrednio do naszych najnowszych tutoriali.
Wyjaśnienie halucynacji AI: dlaczego modele językowe tworzą rzeczy i jak je zmniejszyć
Wyjaśniono halucynacje AI: czym są, dlaczego powstają w modelach językowych, typowe typy, jak je zredukować za pomocą uziemień i podpowiedzi oraz pr…
Przeczytaj artykuł →DevOpsWyjaśnienie zmiennych środowiskowych: pliki .env, sekrety i konfiguracja wykonana prawidłowo
Zmienne środowiskowe wyjaśnione na przykładach Pythona, które przeprowadziliśmy: ich odczytywanie i ustawianie, dlaczego każda wartość jest ciągiem …
Przeczytaj artykuł →Tworzenie oprogramowaniaWyjaśnienie ograniczenia szybkości interfejsu API: algorytmy, nagłówki i obsługa błędów 429
Ograniczanie szybkości API wyjaśnione za pomocą przeprowadzonej przez nas symulacji: zasobnik tokenów, stałe okno, przesuwane okno, 429 odpowiedzi, …
Przeczytaj artykuł →Automatyzacja testówWyśmiewanie w Pythonie: unittest.mock, patch i błędy, które sprawiają, że testy kłamią
Wyśmiewanie w Pythonie za pomocą unittest.mock, przetestowane: Mock i zwracana wartość, efekt uboczny, łatanie tam, gdzie używana jest nazwa, specyf…
Przeczytaj artykuł →Testowanie oprogramowaniaWyjaśnienie zasięgu kodu: pokrycie linii i oddziału oraz co naprawdę oznacza 100%
Wyjaśnienie pokrycia kodu za pomocą prawdziwego pliku cover.py: pokrycie linii, gałęzi i warunków, przeczytanie raportu, dlaczego 100% pokrycia może…
Przeczytaj artykuł →Bazy danych i SQLDELETE vs TRUNCATE vs DROP w SQL: różnice, wycofywanie i kiedy używać każdego z nich
DELETE vs TRUNCATE vs DROP wyjaśnione za pomocą przetestowanego SQL: co każdy usuwa, wycofywanie, wyzwalacze, resetowanie tożsamości, prędkość i czy…
Przeczytaj artykuł →Bazy danych i SQLWyjaśnienie widoków SQL: tworzenie, używanie i unikanie pułapek wraz z przykładami
Widoki SQL wyjaśnione za pomocą zapytań, które uruchomiliśmy: tworzenie widoku, wyniki na żywo, ukrywanie kolumn, wydajność, widoki z możliwością ak…
Przeczytaj artykuł →Tworzenie oprogramowaniaInterfejs TypeScript a typ: rzeczywiste różnice, testowane za pomocą kompilatora
Interfejs TypeScript a typ, sprawdzony z prawdziwym kompilatorem: co oba mogą zrobić, co tylko jeden, łączenie deklaracji, rozszerzenia a przecięcia…
Przeczytaj artykuł →Tworzenie oprogramowaniaPython *args i **kwargs wyjaśnione: elastyczne funkcje z przejrzystymi przykładami
Python *args i **kwargs wyjaśnione za pomocą uruchomionego przez nas kodu: pakowanie i rozpakowywanie, kolejność parametrów, argumenty zawierające t…
Przeczytaj artykuł →Tworzenie oprogramowaniaFunkcje Lambda w Pythonie: składnia, rzeczywiste zastosowania i kiedy ich nie używać
Funkcje lambda w Pythonie wyjaśnione za pomocą uruchomionego przez nas kodu: składnia, sortowanie za pomocą klucza, mapa i filtr, domknięcia, pułapk…
Przeczytaj artykuł →Sztuczna inteligencjaKim są agenci AI? Jak one działają, dzięki prostej pętli agenta, którą możesz uruchomić
Kim są agenci AI? Prosty przewodnik po pętli agenta, narzędziach, pamięci i poręczach, z małą pętlą w Pythonie, którą uruchomiliśmy, prawdziwymi zag…
Przeczytaj artykuł →DevOpsMonitorowanie a obserwowalność: prawdziwa różnica z logami, wskaźnikami i śladami
Wyjaśnienie monitorowania a obserwowalności: znane i nieznane awarie, dzienniki, metryki i ślady, opis incydentu przy kasie, złote sygnały, OpenTele…
Przeczytaj artykuł →DevOpsWoluminy platformy Docker a mocowania powiązań: utrwalanie danych kontenera we właściwy sposób
Wyjaśniono woluminy Dockera a montowanie powiązań: dlaczego dane kontenera znikają, nazwane woluminy, montowanie powiązań, tmpfs, przykłady tworzeni…
Przeczytaj artykuł →Automatyzacja testówTDD vs BDD: kluczowe różnice, jedna funkcja zbudowana w obie strony i kiedy używać każdej z nich
TDD vs BDD wyjaśnione za pomocą jednej funkcji rabatowej zbudowanej w obie strony: refaktoryzacja czerwono-zielona z uruchomionym przez nas kodem, s…
Przeczytaj artykuł →Tworzenie oprogramowaniaGit merge vs rebase: różnice, przykłady i kiedy czego używać
Git merge vs rebase wyjaśnione na prawdziwym wyniku logu, z tabelą porównawczą, złotą zasadą rebase i bezpiecznym procesem pracy zespołu.
Przeczytaj artykuł →Tworzenie oprogramowaniaPython list comprehension: składnia, przykłady i kiedy jej unikać
Python list comprehension wyjaśnione: składnia, filtrowanie, if-else, zagnieżdżone pętle, zmierzone czasy i sytuacje, w których zwykła pętla for jes…
Przeczytaj artykuł →Bazy danych i SQLSQL JOIN – wyjaśnienie z przykładami (Inner, Left, Right, Full)
Zrozum złączenia SQL krok po kroku na przykładowych tabelach i zapytaniach: INNER, LEFT, RIGHT, FULL, CROSS i SELF, plus typowe błędy i wskazówki wy…
Przeczytaj artykuł →