Eu vim com:
drop table if exists idtemp;
create temp table idtemp as
select documentid from taskflag where taskid='coref' and state = 2
order by statechanged asc limit howmany;
create unique index on idtemp(documentid);
-- trim taskflag to the first N docs ordered by coref.
delete from taskflag where documentid not in (select documentid from idtemp) ;
Isso é muito lento quando há 120 mil registros em taskflag e estou mantendo 10 mil.
Taskflag se parece com:
\d taskflag
Table "public.taskflag"
Column | Type | Modifiers
--------------+-----------------------------+-----------
documentid | character varying(64) | not null
taskid | character varying(64) | not null
state | smallint |
statechanged | timestamp without time zone |
Indexes:
"taskflag_pkey" PRIMARY KEY, btree (documentid, taskid)
"task_index2" btree (documentid)
"task_index4" btree (taskid, state, statechanged)
Explique disse:
QUERY PLAN
----------------------------------------------------------------------------------
Delete on taskflag (cost=0.00..105811822.25 rows=223210 width=6)
-> Seq Scan on taskflag (cost=0.00..105811822.25 rows=223210 width=6)
Filter: (NOT (SubPlan 1))
SubPlan 1
-> Materialize (cost=0.00..449.00 rows=10000 width=146)
-> Seq Scan on idtemp (cost=0.00..184.00 rows=10000 width=146)
(6 rows)
Devo apenas providenciar para que a tabela temporária contenha os que estou mantendo?
A otimização mais fácil provavelmente seria permitir que o planejador usasse um hash anti-junção, reescrevendo a consulta como:
também pode ser necessário ANALISAR a tabela temporária imediatamente após preenchê-la.
Eu configurei um teste. Tentar excluir da maneira que você fez fornece praticamente o mesmo plano de consulta. Se você executar um
ANALYZE idtemp
antes de excluir, o plano muda para o seguinte:E a maneira como a_horse_with_no_name sugeriu:
Na minha caixa de teste, não tive paciência para esperar a sua versão terminar :) A primeira versão
ANALYZE
completa um pouco mais de 1 segundo (mas leva mais de meio segundo para executar oINSERT
e oCREATE INDEX
, o que significa cerca de 2 segundos no total), o reformuladoDELETE
apenas um pouco menos de 1 segundo.A segunda sugestão de @a_horse_with_no_name (veja o comentário abaixo) com o seguinte código
também leva cerca de 900 ms, o que significa que, neste caso específico (com meus dados de teste específicos), essa abordagem é bastante competitiva. Se sua
taskflag
tabela tivesse objetos dependentes, não funcionaria.