CASCADE DELETE nur einmal

199

Ich habe eine Postgresql-Datenbank, in der ich einige kaskadierende Löschvorgänge ausführen möchte. Die Tabellen werden jedoch nicht mit der Regel ON DELETE CASCADE eingerichtet. Gibt es eine Möglichkeit, einen Löschvorgang durchzuführen und Postgresql anzuweisen, ihn nur einmal zu kaskadieren? Etwas Äquivalentes zu

DELETE FROM some_table CASCADE;

Die Antworten auf diese ältere Frage lassen den Eindruck entstehen, dass es keine solche Lösung gibt, aber ich dachte, ich würde diese Frage explizit stellen, nur um sicherzugehen.

Eli Courtwright
quelle
Bitte beachten Sie meine benutzerdefinierte Funktion unten. Dies ist mit bestimmten Einschränkungen möglich.
Joe Love

Antworten:

175

Nein. Um dies nur einmal zu tun, schreiben Sie einfach die delete-Anweisung für die Tabelle, die Sie kaskadieren möchten.

DELETE FROM some_child_table WHERE some_fk_field IN (SELECT some_id FROM some_Table);
DELETE FROM some_table;
Palehorse
quelle
12
Dies funktioniert nicht unbedingt, da möglicherweise andere Fremdschlüssel von der ursprünglichen Kaskadierung (Rekursion) kaskadiert werden. Sie können sogar in eine Schleife geraten, in der sich Tabelle a auf b bezieht, die sich auf a bezieht. Um dies im Allgemeinen zu erreichen, siehe meine Tabelle unten, aber es gibt einige Einschränkungen. Wenn Sie eine einfache Tabelleneinrichtung haben, versuchen Sie es mit dem obigen Code. Es ist einfacher zu verstehen, was Sie tun.
Joe Love
2
Einfach, sicher. Sie sollten sie in einer einzigen Transaktion ausführen, wenn Sie Dichteeinfügungen haben.
İsmail Yavuz
40

Wenn Sie wirklich wollen, DELETE FROM some_table CASCADE; was bedeutet " Alle Zeilen aus der Tabelle entfernensome_table ", können Sie TRUNCATEanstelle von DELETEund CASCADEwird immer unterstützt. Wenn Sie jedoch selektives Löschen mit einer whereKlausel verwenden möchten , TRUNCATEist dies nicht gut genug.

VERWENDUNG MIT PFLEGE - Hiermit werden alle Zeilen aller Tabellen gelöscht , für die eine Fremdschlüsseleinschränkung gilt, some_tablesowie alle Tabellen, für die diese Tabellen usw. eingeschränkt sind.

Postgres unterstützt CASCADEmit dem Befehl TRUNCATE :

TRUNCATE some_table CASCADE;

Handlich ist dies eine Transaktion (dh kann zurückgesetzt werden), obwohl sie nicht vollständig von anderen gleichzeitigen Transaktionen isoliert ist und mehrere andere Einschränkungen aufweist. Lesen Sie die Dokumente für Details.

DanC
quelle
226
klar "ein paar kaskadierende Löschungen" ≠ alle Daten aus der Tabelle
löschen
33
Dadurch werden alle Zeilen aller Tabellen gelöscht, für die eine Fremdschlüsseleinschränkung für some_table gilt, und alle Tabellen, für die Einschränkungen für diese Tabellen usw. gelten. Dies ist möglicherweise sehr gefährlich.
AJP
56
in acht nehmen. Dies ist eine rücksichtslose Antwort.
Jordan Arseno
4
Jemand hat diese Antwort zum Löschen markiert - vermutlich, weil er damit nicht einverstanden ist. In diesem Fall ist die richtige Vorgehensweise, abzustimmen und nicht zu kennzeichnen.
Wai Ha Lee
7
Er hat die Warnung oben. Wenn Sie dies ignorieren, kann Ihnen niemand helfen. Ich denke, Ihre "copyPaste" -Nutzer sind hier die wirkliche Gefahr.
BluE
28

Ich habe eine (rekursive) Funktion geschrieben, um jede Zeile basierend auf ihrem Primärschlüssel zu löschen. Ich habe dies geschrieben, weil ich meine Einschränkungen nicht als "On Delete Cascade" erstellen wollte. Ich wollte in der Lage sein, komplexe Datensätze (als DBA) zu löschen, aber meinen Programmierern nicht erlauben, das Löschen zu kaskadieren, ohne über alle Auswirkungen nachzudenken. Ich teste diese Funktion immer noch, daher kann es zu Fehlern kommen - aber versuchen Sie es bitte nicht, wenn Ihre Datenbank mehrspaltige Primärschlüssel (und damit Fremdschlüssel) enthält. Außerdem müssen alle Schlüssel in Zeichenfolgenform dargestellt werden können, sie können jedoch auch so geschrieben werden, dass diese Einschränkung nicht besteht. Ich benutze diese Funktion sowieso SEHR SPAREN, ich schätze meine Daten zu sehr, um die kaskadierenden Einschränkungen für alles zu aktivieren. Grundsätzlich wird diese Funktion im Schema, im Tabellennamen und im Primärwert (in Zeichenfolgenform) übergeben. Zunächst werden Fremdschlüssel in dieser Tabelle gefunden, und es wird sichergestellt, dass keine Daten vorhanden sind. Wenn dies der Fall ist, werden die gefundenen Daten rekursiv aufgerufen. Es verwendet ein Array von Daten, die bereits zum Löschen markiert sind, um Endlosschleifen zu verhindern. Bitte testen Sie es und lassen Sie mich wissen, wie es bei Ihnen funktioniert. Hinweis: Es ist etwas langsam. Ich nenne es so: select delete_cascade('public','my_table','1');

create or replace function delete_cascade(p_schema varchar, p_table varchar, p_key varchar, p_recursion varchar[] default null)
 returns integer as $$
declare
    rx record;
    rd record;
    v_sql varchar;
    v_recursion_key varchar;
    recnum integer;
    v_primary_key varchar;
    v_rows integer;
begin
    recnum := 0;
    select ccu.column_name into v_primary_key
        from
        information_schema.table_constraints  tc
        join information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema=tc.constraint_schema
        and tc.constraint_type='PRIMARY KEY'
        and tc.table_name=p_table
        and tc.table_schema=p_schema;

    for rx in (
        select kcu.table_name as foreign_table_name, 
        kcu.column_name as foreign_column_name, 
        kcu.table_schema foreign_table_schema,
        kcu2.column_name as foreign_table_primary_key
        from information_schema.constraint_column_usage ccu
        join information_schema.table_constraints tc on tc.constraint_name=ccu.constraint_name and tc.constraint_catalog=ccu.constraint_catalog and ccu.constraint_schema=ccu.constraint_schema 
        join information_schema.key_column_usage kcu on kcu.constraint_name=ccu.constraint_name and kcu.constraint_catalog=ccu.constraint_catalog and kcu.constraint_schema=ccu.constraint_schema
        join information_schema.table_constraints tc2 on tc2.table_name=kcu.table_name and tc2.table_schema=kcu.table_schema
        join information_schema.key_column_usage kcu2 on kcu2.constraint_name=tc2.constraint_name and kcu2.constraint_catalog=tc2.constraint_catalog and kcu2.constraint_schema=tc2.constraint_schema
        where ccu.table_name=p_table  and ccu.table_schema=p_schema
        and TC.CONSTRAINT_TYPE='FOREIGN KEY'
        and tc2.constraint_type='PRIMARY KEY'
)
    loop
        v_sql := 'select '||rx.foreign_table_primary_key||' as key from '||rx.foreign_table_schema||'.'||rx.foreign_table_name||'
            where '||rx.foreign_column_name||'='||quote_literal(p_key)||' for update';
        --raise notice '%',v_sql;
        --found a foreign key, now find the primary keys for any data that exists in any of those tables.
        for rd in execute v_sql
        loop
            v_recursion_key=rx.foreign_table_schema||'.'||rx.foreign_table_name||'.'||rx.foreign_column_name||'='||rd.key;
            if (v_recursion_key = any (p_recursion)) then
                --raise notice 'Avoiding infinite loop';
            else
                --raise notice 'Recursing to %,%',rx.foreign_table_name, rd.key;
                recnum:= recnum +delete_cascade(rx.foreign_table_schema::varchar, rx.foreign_table_name::varchar, rd.key::varchar, p_recursion||v_recursion_key);
            end if;
        end loop;
    end loop;
    begin
    --actually delete original record.
    v_sql := 'delete from '||p_schema||'.'||p_table||' where '||v_primary_key||'='||quote_literal(p_key);
    execute v_sql;
    get diagnostics v_rows= row_count;
    --raise notice 'Deleting %.% %=%',p_schema,p_table,v_primary_key,p_key;
    recnum:= recnum +v_rows;
    exception when others then recnum=0;
    end;

    return recnum;
end;
$$
language PLPGSQL;
Joe Love
quelle
Dies geschieht ständig, insbesondere bei selbstreferenzierenden Tabellen. Stellen Sie sich ein Unternehmen mit unterschiedlichen Managementebenen in verschiedenen Abteilungen oder eine generische hierarchische Taxonomie vor. Ja, ich stimme zu, dass diese Funktion nicht die absolut beste seit geschnittenem Brot ist, aber sie ist ein nützliches Werkzeug in der richtigen Situation.
Joe Love
Wenn Sie es neu schreiben, akzeptieren Sie ein Array von IDs und generieren Sie auch Abfragen, die einen INOperator mit Unterauswahl anstelle von =(also Schritt zur Verwendung der Mengenlogik) verwenden. Es würde viel schneller werden.
Hubbitus
2
Vielen Dank für Ihre Lösung. Ich habe einige Tests geschrieben und musste einen Datensatz löschen. Ich hatte Probleme, diesen Löschvorgang zu kaskadieren. Ihre Funktion hat wirklich gut funktioniert!
Fernando Camargo
1
@ JoeLove Welches Geschwindigkeitsproblem hast du? In dieser Situation ist Rekursion für mich eine einzige richtige Lösung.
Hubbitus
1
@arthur Sie könnten wahrscheinlich eine Version von row -> json -> text verwenden, um dies zu erledigen, aber ich bin nicht so weit gegangen. Ich habe im Laufe der Jahre herausgefunden, dass ein einzelner Primärschlüssel (mit potenziellen Sekundärschlüsseln) aus vielen Gründen gut ist.
Joe Love
17

Wenn ich das richtig verstehe, sollten Sie in der Lage sein, das zu tun, was Sie wollen, indem Sie die Fremdschlüsseleinschränkung löschen, eine neue hinzufügen (die kaskadiert), Ihre Aufgaben erledigen und die einschränkende Fremdschlüsseleinschränkung neu erstellen.

Beispielsweise:

testing=# create table a (id integer primary key);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "a_pkey" for table "a"
CREATE TABLE
testing=# create table b (id integer references a);
CREATE TABLE

-- put some data in the table
testing=# insert into a values(1);
INSERT 0 1
testing=# insert into a values(2);
INSERT 0 1
testing=# insert into b values(2);
INSERT 0 1
testing=# insert into b values(1);
INSERT 0 1

-- restricting works
testing=# delete from a where id=1;
ERROR:  update or delete on table "a" violates foreign key constraint "b_id_fkey" on table "b"
DETAIL:  Key (id)=(1) is still referenced from table "b".

-- find the name of the constraint
testing=# \d b;
       Table "public.b"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id)

-- drop the constraint
testing=# alter table b drop constraint b_a_id_fkey;
ALTER TABLE

-- create a cascading one
testing=# alter table b add FOREIGN KEY (id) references a(id) on delete cascade; 
ALTER TABLE

testing=# delete from a where id=1;
DELETE 1
testing=# select * from a;
 id 
----
  2
(1 row)

testing=# select * from b;
 id 
----
  2
(1 row)

-- it works, do your stuff.
-- [stuff]

-- recreate the previous state
testing=# \d b;
       Table "public.b"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id) ON DELETE CASCADE

testing=# alter table b drop constraint b_id_fkey;
ALTER TABLE
testing=# alter table b add FOREIGN KEY (id) references a(id) on delete restrict; 
ALTER TABLE

Natürlich sollten Sie solche Dinge aus Gründen Ihrer geistigen Gesundheit in ein Verfahren abstrahieren.

Ryszard Szopa
quelle
4
Unter der Annahme, dass der Fremdschlüssel verhindern soll, dass die Datenbank inkonsistent wird, ist dies nicht der richtige Weg. Sie können den "bösen" Eintrag jetzt löschen, aber Sie hinterlassen viele Zombiesplitter, die in Zukunft Probleme verursachen könnten
Sprinterfreak
1
Welche Scherben meinst du genau? Die Datensätze werden per Kaskade gelöscht, es sollte keine Inkonsistenz geben.
Pedro Borges
1
Anstatt sich über "böse Shards" Gedanken zu machen (kaskadierende Einschränkungen sind immer noch konsistent), wäre ich MEHR besorgt darüber, dass die Kaskadierung nicht weit genug geht - wenn für die gelöschten Datensätze weitere gelöschte Datensätze erforderlich sind, müssen diese Einschränkungen geändert werden um auch eine Kaskadierung zu gewährleisten. (oder verwenden Sie die oben beschriebene Funktion, um dieses Szenario zu vermeiden) ... Eine letzte Empfehlung auf jeden Fall: VERWENDEN SIE EINE TRANSAKTION, damit Sie sie zurücksetzen können, wenn sie schief geht.
Joe Love
7

Ich kann die Antwort von Palehorse nicht kommentieren, also habe ich meine eigene Antwort hinzugefügt. Die Logik von Palehorse ist in Ordnung, aber die Effizienz kann bei großen Datenmengen schlecht sein.

DELETE FROM some_child_table sct 
 WHERE exists (SELECT FROM some_Table st 
                WHERE sct.some_fk_fiel=st.some_id);

DELETE FROM some_table;

Es ist schneller, wenn Sie Indizes für Spalten haben und der Datensatz größer als wenige Datensätze ist.

Grzegorz Grabek
quelle
7

Ja, wie andere gesagt haben, gibt es kein praktisches 'DELETE FROM my_table ... CASCADE' (oder ein gleichwertiges). Um nicht kaskadierende fremdschlüsselgeschützte untergeordnete Datensätze und ihre referenzierten Vorfahren zu löschen, haben Sie folgende Möglichkeiten:

  • Führen Sie alle Löschvorgänge explizit nacheinander ab, beginnend mit untergeordneten Tabellen (obwohl dies nicht funktioniert, wenn Sie Zirkelverweise haben). oder
  • Führen Sie alle Löschungen explizit in einer einzigen (möglicherweise massiven) Abfrage durch. oder
  • Angenommen, Ihre nicht kaskadierenden Fremdschlüsseleinschränkungen wurden als "ON DELETE NO ACTION DEFERRABLE" erstellt. Führen Sie alle Löschvorgänge explizit in einer einzigen Transaktion aus. oder
  • Löschen Sie vorübergehend die Einschränkungen "Keine Aktion" und "Einschränken" von Fremdschlüsseln im Diagramm, erstellen Sie sie als CASCADE neu, löschen Sie die betreffenden Vorfahren, löschen Sie die Fremdschlüsseleinschränkungen erneut und erstellen Sie sie schließlich so, wie sie ursprünglich waren (wodurch die Integrität von vorübergehend geschwächt wird) deine Daten); oder
  • Etwas, das wahrscheinlich genauso viel Spaß macht.

Ich gehe davon aus, dass das Umgehen von Fremdschlüsseleinschränkungen nicht bequem ist. aber ich verstehe, warum Sie es unter bestimmten Umständen tun möchten. Wenn es etwas ist, das Sie mit einer gewissen Häufigkeit tun, und wenn Sie bereit sind, die Weisheit von Datenbankadministratoren überall zu missachten, möchten Sie es möglicherweise mit einem Verfahren automatisieren.

Ich bin vor ein paar Monaten hierher gekommen, um eine Antwort auf die Frage "CASCADE DELETE nur einmal" zu suchen (ursprünglich vor über einem Jahrzehnt gestellt!). Ich habe einige Meilen aus der cleveren Lösung von Joe Love (und der Variante von Thomas CG de Vilhena) herausgeholt, aber am Ende hatte mein Anwendungsfall besondere Anforderungen (zum Beispiel die Behandlung von zirkularinternen Zirkelverweisen), die mich zu einem anderen Ansatz zwangen. Dieser Ansatz wurde letztendlich rekursiv gelöscht (PG 10.10).

Ich benutze recursively_delete jetzt schon eine Weile in der Produktion und fühle mich schließlich (vorsichtig) sicher genug, um es anderen zur Verfügung zu stellen, die hier auf der Suche nach Ideen landen könnten. Wie bei der Lösung von Joe Love können Sie ganze Datendiagramme löschen, als ob alle Fremdschlüsseleinschränkungen in Ihrer Datenbank vorübergehend auf CASCADE gesetzt wären, bietet jedoch einige zusätzliche Funktionen:

  • Bietet eine ASCII-Vorschau des Löschziels und seines Diagramms der abhängigen Personen.
  • Führt das Löschen in einer einzelnen Abfrage mit rekursiven CTEs durch.
  • Behandelt zirkuläre Abhängigkeiten, Intra- und Inter-Table.
  • Behandelt zusammengesetzte Schlüssel.
  • Überspringt die Einschränkungen "Standard festlegen" und "Null festlegen".
TRL
quelle
Ich erhalte eine Fehlermeldung: FEHLER: Array muss eine gerade Anzahl von Elementen haben. Dabei gilt Folgendes: PL / pgSQL-Funktion _recursively_delete (Regclass, Text [], Ganzzahl, JSONB, Ganzzahl, Text [], JSONB, JSONB) Zeile 15 bei der Zuweisungs-SQL-Anweisung "SELECT * FROM _recursively_delete (ARG_table, VAR_pk_col_names)" PL / pgSQL-Funktion recursively_delete (regclass, anyelement, boolean) Zeile 73 in der SQL-Anweisung
Joe Love
Hey, @JoeLove. Danke, dass du es ausprobiert hast. Können Sie mir Schritte zur Reproduktion geben? Und was ist deine Version von PG?
TRL
Ich bin mir nicht sicher, ob das helfen wird. Aber ich habe gerade Ihre Funktionen erstellt und dann den folgenden Code ausgeführt: select recursively_delete ('dallas.vendor', 1094, false) Nach einigem Debuggen stelle ich fest, dass dies sofort stirbt - was bedeutet, dass es der erste Aufruf ist auf die Funktion, nicht nachdem mehrere Dinge getan wurden. Als Referenz verwende ich PG 10.8
Joe Love
@JoeLove, bitte versuchen Sie es mit dem Zweig trl-fix-array_must_have_even_number_of_element ( github.com/trlorenz/PG-recursively_delete/pull/2 ).
TRL
Versuchte diesen Zweig und es hat den ursprünglichen Fehler behoben. Leider ist es nicht schneller als meine Originalversion (was möglicherweise nicht Ihr Grund war, dies überhaupt zu schreiben). Ich arbeite an einem weiteren Versuch, bei dem doppelte Fremdschlüssel mit "on delete cascade" erstellt werden, dann der ursprüngliche Datensatz gelöscht und dann alle neu erstellten Fremdschlüssel gelöscht werden
Joe Love
3

Um dies zu automatisieren, können Sie die Fremdschlüsseleinschränkung mit definieren ON DELETE CASCADE.
Ich zitiere das Handbuch der Fremdschlüsseleinschränkungen :

CASCADE Gibt an, dass beim Löschen einer referenzierten Zeile auch die referenzierenden Zeilen automatisch gelöscht werden sollen.

atiruz
quelle
1
Obwohl dies das OP nicht anspricht, ist es eine gute Planung, wann Zeilen mit Fremdschlüsseln gelöscht werden müssen. Wie Ben Franklin sagte: "Eine Unze Prävention ist ein Pfund Heilung wert."
Jesuisme
1
Ich habe festgestellt, dass diese Lösung sehr gefährlich sein kann, wenn Ihre App einen Datensatz mit vielen Geschwistern löscht und Sie anstelle eines kleinen Fehlers einen riesigen Datensatz dauerhaft gelöscht haben.
Joe Love
2

Ich nahm die Antwort von Joe Love und schrieb sie mit dem INOperator mit Unterauswahl neu, anstatt =die Funktion schneller zu machen (gemäß Hubbitus 'Vorschlag):

create or replace function delete_cascade(p_schema varchar, p_table varchar, p_keys varchar, p_subquery varchar default null, p_foreign_keys varchar[] default array[]::varchar[])
 returns integer as $$
declare

    rx record;
    rd record;
    v_sql varchar;
    v_subquery varchar;
    v_primary_key varchar;
    v_foreign_key varchar;
    v_rows integer;
    recnum integer;

begin

    recnum := 0;
    select ccu.column_name into v_primary_key
        from
        information_schema.table_constraints  tc
        join information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema=tc.constraint_schema
        and tc.constraint_type='PRIMARY KEY'
        and tc.table_name=p_table
        and tc.table_schema=p_schema;

    for rx in (
        select kcu.table_name as foreign_table_name, 
        kcu.column_name as foreign_column_name, 
        kcu.table_schema foreign_table_schema,
        kcu2.column_name as foreign_table_primary_key
        from information_schema.constraint_column_usage ccu
        join information_schema.table_constraints tc on tc.constraint_name=ccu.constraint_name and tc.constraint_catalog=ccu.constraint_catalog and ccu.constraint_schema=ccu.constraint_schema 
        join information_schema.key_column_usage kcu on kcu.constraint_name=ccu.constraint_name and kcu.constraint_catalog=ccu.constraint_catalog and kcu.constraint_schema=ccu.constraint_schema
        join information_schema.table_constraints tc2 on tc2.table_name=kcu.table_name and tc2.table_schema=kcu.table_schema
        join information_schema.key_column_usage kcu2 on kcu2.constraint_name=tc2.constraint_name and kcu2.constraint_catalog=tc2.constraint_catalog and kcu2.constraint_schema=tc2.constraint_schema
        where ccu.table_name=p_table  and ccu.table_schema=p_schema
        and TC.CONSTRAINT_TYPE='FOREIGN KEY'
        and tc2.constraint_type='PRIMARY KEY'
)
    loop
        v_foreign_key := rx.foreign_table_schema||'.'||rx.foreign_table_name||'.'||rx.foreign_column_name;
        v_subquery := 'select "'||rx.foreign_table_primary_key||'" as key from '||rx.foreign_table_schema||'."'||rx.foreign_table_name||'"
             where "'||rx.foreign_column_name||'"in('||coalesce(p_keys, p_subquery)||') for update';
        if p_foreign_keys @> ARRAY[v_foreign_key] then
            --raise notice 'circular recursion detected';
        else
            p_foreign_keys := array_append(p_foreign_keys, v_foreign_key);
            recnum:= recnum + delete_cascade(rx.foreign_table_schema, rx.foreign_table_name, null, v_subquery, p_foreign_keys);
            p_foreign_keys := array_remove(p_foreign_keys, v_foreign_key);
        end if;
    end loop;

    begin
        if (coalesce(p_keys, p_subquery) <> '') then
            v_sql := 'delete from '||p_schema||'."'||p_table||'" where "'||v_primary_key||'"in('||coalesce(p_keys, p_subquery)||')';
            --raise notice '%',v_sql;
            execute v_sql;
            get diagnostics v_rows = row_count;
            recnum := recnum + v_rows;
        end if;
        exception when others then recnum=0;
    end;

    return recnum;

end;
$$
language PLPGSQL;
Thomas CG de Vilhena
quelle
2
Ich muss mir das ansehen und sehen, wie gut es mit selbstreferenzierenden Einschränkungen und dergleichen funktioniert. Ich habe versucht, etwas Ähnliches zu tun, habe aber aufgehört, es voll funktionsfähig zu machen. Wenn Ihre Lösung für mich funktioniert, werde ich sie implementieren. Dies ist eines von vielen dba-Tools, die verpackt und auf Github oder so etwas installiert werden sollten.
Joe Love
Ich habe mittelgroße Datenbanken für ein CMS mit mehreren Mandanten (Clients verwenden alle dieselben Tabellen). Meine Version (ohne "in") scheint ziemlich langsam zu laufen, um alle Spuren eines alten Clients zu löschen ... Ich bin daran interessiert, dies mit einigen Modelldaten auszuprobieren, um die Geschwindigkeit zu vergleichen. Hatten Sie etwas zu dem Geschwindigkeitsunterschied, den Sie in Ihren Anwendungsfällen festgestellt haben?
Joe Love
Für meinen Anwendungsfall habe ich bei Verwendung des inOperators und von Unterabfragen eine Beschleunigung in der Größenordnung von 10x festgestellt .
Thomas CG de Vilhena
1

Das Löschen mit der Kaskadenoption gilt nur für Tabellen mit definierten Fremdschlüsseln. Wenn Sie einen Löschvorgang ausführen und dies nicht möglich ist, da dies die Fremdschlüsseleinschränkung verletzen würde, führt die Kaskade dazu, dass die fehlerhaften Zeilen gelöscht werden.

Wenn Sie zugeordnete Zeilen auf diese Weise löschen möchten, müssen Sie zuerst die Fremdschlüssel definieren. Denken Sie auch daran, dass, wenn Sie es nicht ausdrücklich anweisen, eine Transaktion zu starten, oder wenn Sie die Standardeinstellungen ändern, eine automatische Festschreibung durchgeführt wird, deren Bereinigung sehr zeitaufwändig sein kann.

Grant Johnson
quelle
2
Grants Antwort ist teilweise falsch - Postgresql unterstützt CASCADE bei DELETE-Abfragen nicht. postgresql.org/docs/8.4/static/dml-delete.html
Fredrik Wendt
Irgendeine Idee, warum es bei der Löschabfrage nicht unterstützt wird?
Teifion
2
Es gibt keine Möglichkeit, "mit Kaskade zu löschen" für eine Tabelle, die nicht entsprechend eingerichtet wurde, dh für die die Fremdschlüsseleinschränkung nicht als ON DELETE CASCADE definiert wurde, worum es bei der Frage ursprünglich ging.
Lensovet
Als Antwort auf diese Frage ist dies völlig falsch. Es gibt keine Möglichkeit, CASCADE einmal zu verwenden.
Jeremy