Imagine a tabela a seguir sobre donos de gatos.
drop table if exists owners cascade;
create table owners(
id bigint primary key generated always as identity ,
name text not null
)
;
insert into owners(name)
select random()::text from generate_series(1,20000);
--insert 200,000 owners records
Quando excluo alguns dos registros de proprietários, é bem rápido:
delete from owners
where id %10 = 0;
20.000 linhas afetadas em 85 ms
Agora eu adiciono uma tabela chamada 'cats' que se refere aos proprietários:
drop table if exists cats;
create table cats(
id serial primary key ,
name varchar(20000) not null,
owner_id int not null references owners(id)
);
--insert 1bn cats records
insert into cats(name, owner_id)
select
random()::text,
owners.id
from generate_series(1,10), owners;
Vamos deletar alguns donos, mas primeiro temos que deletar os gatos que esses donos 'possuem':
--delete the records in cats so we don't get a foreign key constraint violation
delete from cats
where owner_id %10 = 1;
---now we do the same delete on owners as we did before
delete from owners
where id %10 = 1;
2000 linhas afetadas em 25 s 828 ms
Por que a segunda exclusão dos proprietários é ~5000 vezes mais lenta do que quando não tínhamos a tabela de gatos?
É a verificação se o proprietário ainda é referenciado pela
cats
tabela durante o DELETE. A verificação é feita essencialmente usando umselect * from cats where owner_id = ?
para cada proprietário que você exclui.Você pode acelerar a verificação criando um índice na coluna de chave estrangeira: