CASCADE XÓA chỉ một lần


200

Tôi có một cơ sở dữ liệu Postgresql mà tôi muốn thực hiện một vài thao tác xóa tầng. Tuy nhiên, các bảng không được thiết lập với quy tắc BẬT XÓA CASCADE. Có cách nào để tôi có thể thực hiện xóa và nói với Postgresql xếp tầng này chỉ một lần không? Một cái gì đó tương đương với

DELETE FROM some_table CASCADE;

Các câu trả lời cho câu hỏi cũ hơn này dường như không có giải pháp nào như vậy tồn tại, nhưng tôi đoán rằng tôi sẽ hỏi câu hỏi này một cách rõ ràng chỉ để chắc chắn.


Xin vui lòng xem chức năng tùy chỉnh của tôi dưới đây. Điều đó có thể với một số hạn chế nhất định.
Joe Love

Câu trả lời:


175

Không. Để làm điều đó chỉ một lần bạn chỉ cần viết câu lệnh xóa cho bảng bạn muốn xếp tầng.

DELETE FROM some_child_table WHERE some_fk_field IN (SELECT some_id FROM some_Table);
DELETE FROM some_table;

12
Điều này không nhất thiết phải hoạt động vì có thể có các khóa ngoại khác xếp tầng từ tầng gốc (đệ quy). Bạn thậm chí có thể đi vào một vòng lặp trong đó bảng a đề cập đến b trong đó đề cập đến a. Để đạt được điều này theo nghĩa chung, xem bảng của tôi dưới đây, nhưng nó có một số hạn chế. Nếu bạn có một thiết lập bảng đơn giản thì hãy thử mã ở trên, sẽ dễ hiểu hơn những gì bạn đang làm.
Joe yêu

2
Đơn giản, an toàn. Bạn nên chạy chúng trong một giao dịch nếu bạn có mật độ chèn.
İsmail Yavuz

40

Nếu bạn thực sự muốn DELETE FROM some_table CASCADE; có nghĩa là " xóa tất cả các hàng khỏi bảngsome_table ", bạn có thể sử dụng TRUNCATEthay vì DELETECASCADEluôn được hỗ trợ. Tuy nhiên, nếu bạn muốn sử dụng xóa chọn lọc với một wheremệnh đề, TRUNCATEthì không đủ tốt.

SỬ DỤNG VỚI CHĂM SÓC - Điều này sẽ loại bỏ tất cả các hàng của tất cả các bảng có ràng buộc khóa ngoài some_tablevà tất cả các bảng có các ràng buộc trên các bảng đó, v.v.

Postgres hỗ trợ CASCADEvới lệnh TRUNCATE :

TRUNCATE some_table CASCADE;

Handily đây là giao dịch (nghĩa là có thể được khôi phục), mặc dù nó không hoàn toàn tách biệt với các giao dịch đồng thời khác và có một số cảnh báo khác. Đọc tài liệu để biết chi tiết.


226
rõ ràng "một vài lần xóa tầng" bỏ tất cả dữ liệu từ bảng
lensovet

33
Điều này sẽ loại bỏ tất cả các hàng của tất cả các bảng có ràng buộc khóa ngoài trên some_table và tất cả các bảng có ràng buộc trên các bảng đó, v.v ... điều này có khả năng rất nguy hiểm.
AJP

56
coi chừng đây là một câu trả lời liều lĩnh
Jordan Arseno

4
Ai đó đã đánh dấu câu trả lời này để xóa - có lẽ vì họ không đồng ý với nó. Quá trình hành động chính xác trong trường hợp đó là downvote, không gắn cờ.
Wai Ha Lee

7
Ông có cảnh báo trên đầu. Nếu bạn chọn bỏ qua điều đó, không ai có thể giúp bạn. Tôi nghĩ rằng người dùng "copyPaste" của bạn là mối nguy hiểm thực sự ở đây.
BluE

28

Tôi đã viết một hàm (đệ quy) để xóa bất kỳ hàng nào dựa trên khóa chính của nó. Tôi đã viết điều này bởi vì tôi không muốn tạo ra các ràng buộc của mình là "xóa tầng". Tôi muốn có thể xóa các bộ dữ liệu phức tạp (dưới dạng DBA) nhưng không cho phép các lập trình viên của tôi có thể xếp tầng xóa mà không cần suy nghĩ về tất cả các hậu quả. Tôi vẫn đang thử nghiệm chức năng này, vì vậy có thể có lỗi trong đó - nhưng vui lòng không thử nếu DB của bạn có nhiều khóa chính (và do đó là nước ngoài). Ngoài ra, tất cả các khóa phải có thể được biểu diễn dưới dạng chuỗi, nhưng nó có thể được viết theo cách không có hạn chế đó. Dù sao thì tôi cũng sử dụng chức năng RẤT RẤT RẤT NHIỀU, tôi đánh giá dữ liệu của mình quá nhiều để cho phép các ràng buộc xếp tầng trên mọi thứ. Về cơ bản, hàm này được truyền vào lược đồ, tên bảng và giá trị chính (ở dạng chuỗi), và nó sẽ bắt đầu bằng cách tìm bất kỳ khóa ngoại nào trên bảng đó và đảm bảo dữ liệu không tồn tại - nếu có, nó sẽ gọi chính nó trên dữ liệu tìm thấy. Nó sử dụng một mảng dữ liệu đã được đánh dấu để xóa để ngăn chặn các vòng lặp vô hạn. Vui lòng kiểm tra và cho tôi biết làm thế nào nó hoạt động cho bạn. Lưu ý: Nó hơi chậm. Tôi gọi nó như vậy: 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;

Nó xảy ra tất cả các thời gian đặc biệt là với các bảng tự tham khảo. Hãy xem xét một công ty với các tầng quản lý khác nhau trong các phòng ban khác nhau, hoặc một phân loại phân cấp chung. Vâng, tôi đồng ý rằng chức năng này không phải là điều tuyệt vời nhất kể từ khi bánh mì cắt lát, nhưng nó là một công cụ hữu ích trong tình huống phù hợp.
Joe yêu

Nếu bạn viết lại, nó chấp nhận mảng ID và cũng tạo ra các truy vấn sẽ sử dụng INtoán tử với các lựa chọn phụ thay vì =(vì vậy bước sử dụng bộ logic), nó sẽ trở nên nhanh hơn nhiều .
Hubbitus

2
Cảm ơn bạn cho giải pháp của bạn. Tôi viết một số bài kiểm tra và tôi cần xóa một bản ghi và tôi gặp khó khăn khi xếp tầng đó. Chức năng của bạn hoạt động rất tốt!
Fernando Camargo

1
@JoeLove bạn có vấn đề gì về tốc độ? Trong tình huống đó đệ quy là giải pháp duy nhất đúng trong tâm trí của tôi.
Hubbitus

1
@arthur bạn có thể có thể sử dụng một số phiên bản của hàng -> json -> văn bản để hoàn thành nó, tuy nhiên, tôi đã không đi quá xa. Tôi đã tìm thấy qua nhiều năm rằng một khóa chính đơn lẻ (với các khóa phụ tiềm năng) là tốt vì nhiều lý do.
Joe yêu

17

Nếu tôi hiểu chính xác, bạn sẽ có thể làm những gì bạn muốn bằng cách loại bỏ ràng buộc khóa ngoại, thêm một ràng buộc mới (sẽ xếp tầng), thực hiện công cụ của bạn và tạo lại hạn chế khóa ngoại.

Ví dụ:

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

Tất nhiên, bạn nên trừu tượng hóa những thứ như thế vào một thủ tục, vì lợi ích sức khỏe tinh thần của bạn.


4
Trong giả định rằng khóa ngoại khóa ngăn chặn làm những việc khiến cơ sở dữ liệu không nhất quán, đây không phải là cách để giải quyết. Bạn có thể xóa mục "khó chịu" ngay bây giờ nhưng bạn đang để lại rất nhiều mảnh vỡ zombie có thể gây ra vấn đề trong tương lai
Sprinterfreak

1
Những gì bạn có nghĩa là chính xác? các hồ sơ sẽ bị xóa thông qua thác nên không có sự mâu thuẫn.
Pedro Borges

1
thay vì lo lắng về "những mảnh vỡ khó chịu" (các ràng buộc xếp tầng sẽ vẫn nhất quán), tôi sẽ quan tâm nhiều hơn về việc xếp tầng không đủ xa-- nếu các bản ghi bị xóa yêu cầu các bản ghi bị xóa thêm, thì những ràng buộc đó sẽ cần được thay đổi để đảm bảo xếp tầng là tốt. (hoặc sử dụng chức năng tôi đã viết ở trên để tránh tình huống này) ... Một khuyến nghị cuối cùng trong mọi trường hợp: SỬ DỤNG GIAO DỊCH để bạn có thể khôi phục lại nếu gặp sự cố.
Joe yêu

7

Tôi không thể nhận xét câu trả lời của Palehorse vì vậy tôi đã thêm câu trả lời của riêng mình. Logic của Palehorse là ổn nhưng hiệu quả có thể tệ với các tập dữ liệu lớn.

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;

Sẽ nhanh hơn nếu bạn có các chỉ mục trên các cột và tập dữ liệu lớn hơn vài bản ghi.


7

Vâng, như những người khác đã nói, không có tiện ích 'XÓA TỪ my_table ... CASCADE' (hoặc tương đương). Để xóa hồ sơ con không được bảo vệ bằng khóa ngoại và tổ tiên được tham chiếu của chúng, các tùy chọn của bạn bao gồm:

  • Thực hiện tất cả các thao tác xóa một cách rõ ràng, một truy vấn tại một thời điểm, bắt đầu bằng các bảng con (mặc dù điều này sẽ không bay nếu bạn có các tham chiếu vòng tròn); hoặc là
  • Thực hiện tất cả các thao tác xóa một cách rõ ràng trong một truy vấn (có khả năng lớn); hoặc là
  • Giả sử các ràng buộc khóa ngoại không xếp tầng của bạn đã được tạo là 'TRÊN XÓA KHÔNG CÓ QUYẾT ĐỊNH HÀNH ĐỘNG', thực hiện tất cả các thao tác xóa rõ ràng trong một giao dịch; hoặc là
  • Tạm thời bỏ các ràng buộc khóa ngoài 'không hành động' và 'hạn chế' trong biểu đồ, tạo lại chúng dưới dạng CASCADE, xóa tổ tiên vi phạm, xóa lại các ràng buộc khóa ngoại và cuối cùng tạo lại chúng như ban đầu (do đó tạm thời làm suy yếu tính toàn vẹn của dữ liệu của bạn); hoặc là
  • Một cái gì đó có lẽ cũng vui không kém.

Đó là mục đích để tránh các ràng buộc khóa ngoại không thuận tiện, tôi giả sử; nhưng tôi hiểu tại sao trong những trường hợp cụ thể bạn muốn làm điều đó. Nếu đó là điều gì đó bạn sẽ thực hiện với một số tần suất và nếu bạn sẵn sàng phát huy trí tuệ của các DBA ở mọi nơi, bạn có thể muốn tự động hóa nó bằng một quy trình.

Tôi đến đây vài tháng trước để tìm câu trả lời cho câu hỏi "CASCADE DELETE chỉ một lần" (ban đầu được hỏi hơn một thập kỷ trước!). Tôi đã nhận được một số dặm từ giải pháp thông minh của Joe Love (và biến thể của Thomas CG de Vilhena), nhưng cuối cùng, trường hợp sử dụng của tôi có những yêu cầu đặc biệt (xử lý các tham chiếu vòng tròn trong bảng), buộc tôi phải thực hiện một cách tiếp cận khác. Cách tiếp cận đó cuối cùng đã trở thành đệ quy_delete (PG 10.10).

Tôi đã sử dụng recursively_delete trong sản xuất một thời gian, bây giờ, và cuối cùng cảm thấy (đủ cẩn thận) đủ tự tin để cung cấp cho những người khác có thể tìm kiếm ý tưởng ở đây. Như với giải pháp của Joe Love, nó cho phép bạn xóa toàn bộ biểu đồ dữ liệu như thể tất cả các ràng buộc khóa ngoại trong cơ sở dữ liệu của bạn được đặt tạm thời thành CASCADE, nhưng cung cấp một vài tính năng bổ sung:

  • Cung cấp bản xem trước ASCII của mục tiêu xóa và biểu đồ phụ thuộc của nó.
  • Thực hiện xóa trong một truy vấn duy nhất bằng cách sử dụng CTE đệ quy.
  • Xử lý các phụ thuộc tròn, nội bộ và liên bảng.
  • Xử lý các phím tổng hợp.
  • Bỏ qua các ràng buộc 'đặt mặc định' và 'đặt null'.

Tôi đang gặp lỗi: ERROR: mảng phải có số phần tử chẵn Trong đó: Hàm PL / pgQuery _recursively_delete (reggroup, text [], số nguyên, jsonb, số nguyên, văn bản [], jsonb, jsonb) dòng 15 khi gán câu lệnh SQL "CHỌN * TỪ _recursively_delete (ARG_table, VAR_pk_col_names)" Hàm PL / pgQuery recursively_delete (reg class, anyelement, boolean) dòng 73 tại câu lệnh SQL
Joe Love

Này, @JoeLove. Cám ơn vì đã thử nó. Bạn có thể cho tôi các bước để tái sản xuất? Và phiên bản PG của bạn là gì?
TRL

Tôi không chắc điều này sẽ giúp. nhưng tôi chỉ tạo các hàm của bạn và sau đó chạy đoạn mã sau: select recursively_delete ('dallas.vendor', 1094, false) Sau khi gỡ lỗi, tôi thấy rằng điều này chết ngay lập tức - có nghĩa là đây là cuộc gọi đầu tiên đến chức năng, không phải sau khi làm nhiều việc. Để tham khảo Tôi đang chạy PG 10.8
Joe Love

@JoeLove, Vui lòng thử chi nhánh trl-fix-Array_must_have_even_number_of_element ( github.com/trlorenz/PG-recursively_delete/pull/2 ).
TRL

Đã thử chi nhánh đó và nó đã sửa lỗi ban đầu. Đáng buồn thay, nó không nhanh hơn phiên bản gốc của tôi (có thể không phải là điểm của bạn khi viết bài này ở nơi đầu tiên). Tôi đang thực hiện một nỗ lực khác để tạo các khóa ngoại lai trùng lặp với "on xóa tầng", sau đó xóa bản ghi gốc, sau đó bỏ tất cả các khóa ngoại mới được tạo,
Joe Love

3

Bạn có thể sử dụng để tự động hóa điều này, bạn có thể xác định ràng buộc khóa ngoài với ON DELETE CASCADE.
Tôi trích dẫn hướng dẫn sử dụng các ràng buộc khóa ngoại :

CASCADE xác định rằng khi một hàng được tham chiếu bị xóa, (các) hàng tham chiếu đó cũng sẽ tự động bị xóa.


1
Mặc dù điều này không giải quyết được OP, nhưng đó là kế hoạch tốt khi các hàng có khóa ngoại cần được xóa. Như Ben Franklin đã nói, "một ounce phòng ngừa đáng giá một pound thuốc chữa bệnh."
Jesuisme

1
Tôi thấy rằng giải pháp này có thể khá nguy hiểm nếu ứng dụng của bạn xóa bản ghi có nhiều anh chị em và thay vì một lỗi nhỏ, bạn đã xóa vĩnh viễn một bộ dữ liệu khổng lồ.
Joe yêu

2

Tôi đã lấy câu trả lời của Joe Love và viết lại bằng cách sử dụng INtoán tử với các lựa chọn phụ thay vì =để làm cho chức năng nhanh hơn (theo đề xuất của Hubbitus):

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;

2
Tôi sẽ phải xem xét điều này và xem nó hoạt động tốt như thế nào với các ràng buộc tự tham chiếu và tương tự. Tôi đã cố gắng làm một cái gì đó tương tự nhưng dừng lại để làm cho nó hoạt động đầy đủ. Nếu giải pháp của bạn hiệu quả với tôi, tôi sẽ thực hiện nó. Đây là một trong nhiều công cụ dba nên được đóng gói và đưa lên github hoặc một cái gì đó.
Joe yêu

Tôi có cơ sở dữ liệu kích thước trung bình cho một CMS nhiều bên thuê (tất cả các máy khách đều có chung các bảng). Phiên bản của tôi (không có "trong") dường như chạy khá chậm để xóa tất cả dấu vết của một khách hàng cũ ... Tôi quan tâm đến việc thử điều này với một số dữ liệu mô phỏng để so sánh tốc độ. Bạn có bất cứ điều gì bạn có thể nói về sự khác biệt tốc độ bạn nhận thấy trong (các) trường hợp sử dụng của bạn không?
Joe yêu

Đối với trường hợp sử dụng của tôi, tôi nhận thấy tăng tốc theo thứ tự 10 lần khi sử dụng intoán tử và truy vấn phụ.
Thomas CG de Vilhena

1

Việc xóa với tùy chọn xếp tầng chỉ áp dụng cho các bảng có khóa ngoại được xác định. Nếu bạn thực hiện xóa và thông báo rằng bạn không thể vì nó sẽ vi phạm ràng buộc khóa ngoại, tầng sẽ khiến nó xóa các hàng vi phạm.

Nếu bạn muốn xóa các hàng liên quan theo cách này, trước tiên bạn cần xác định các khóa ngoại. Ngoài ra, hãy nhớ rằng trừ khi bạn chỉ dẫn rõ ràng để bắt đầu giao dịch hoặc bạn thay đổi mặc định, nó sẽ thực hiện tự động cam kết, việc này có thể rất tốn thời gian để dọn dẹp.


2
Câu trả lời của Grant là một phần sai - Postgresql không hỗ trợ CASCADE trên các truy vấn XÓA. postgresql.org/docs/8.4/static/dml-delete.html
Fredrik Wendt

Bất cứ ý tưởng tại sao nó không được hỗ trợ trên truy vấn xóa?
Teifion

2
không có cách nào để "xóa bằng tầng" trên một bảng chưa được thiết lập tương ứng, nghĩa là ràng buộc khóa ngoại không được xác định là BẬT XÓA CASCADE, đó là câu hỏi ban đầu.
lensovet

Là một câu trả lời cho này câu hỏi, điều này là hoàn toàn sai. Không có cách nào để CASCADE một lần.
Jeremy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.