Você vem de MySQL?  Parece típico de MySQL, porque ele implementa
subconsultas mal.

Não ... É que já tive más experiencias com NOT IN... Onde o LEFT foi
melhor, mas não me lembro exatamente a estrutura das tabelas nem
índices...

        Eu faria:

 SELECT
        <atributos>
   FROM
        <esquema>.tzr_log       AS l
  WHERE l.id_log NOT IN
        (SELECT r.id_log
           FROM <esquema>.tzr_replicated_log    AS r)
;

        Ou com NOT EXISTS, não sei se algum é mais eficiente que o outro no
PostgreSQL.  Teoricamente são equivalentes.

Tempos :

SELECT * FROM tzrepl.tzr_log L
LEFT OUTER JOIN tzrepl.tzr_replicated_log RL
ON RL.id_log = RL.id_log
WHERE RL.id_log IS NULL;
-- 861971 registros em 24078ms

SELECT * FROM tzrepl.tzr_log L
WHERE id_log NOT IN(SELECT id_log FROM tzrepl.tzr_replicated_log)
--861971 registros em  19407ms

SELECT * FROM tzrepl.tzr_log L
WHERE NOT EXISTS(SELECT id_log FROM tzrepl.tzr_replicated_log WHERE
id_log = L.id_log)
-- 861971 registros em  19407ms (Exatamente IGUAL ao NOT IN)

Achei os números bem aceitáveis [1], principalmente por estar em um
servidor de Teste (Bem ruinzinho por sinal)... Mas meu medo é que
conforme esse registros aumentem (e vão aumentar muito), isto comece a
ficar muito lento...

[1] -  A tabela tzr_replicated_log não possui nenhum registro e a
minha previsão para produção é que a razão entre as tabelas seja de no
máximo 6/5 (861971 / 718309) ...
Populei a tabela replicated_log com 718306 registros e :
Estou efetuando os testes para NOT IN, LEFT JOIN, NOT EXISTS e <> ALL
.... Mas está um pouco lento (Já esta executando a mais de uma hora e
nada). - Assim que tiver os resultados eu posta aqui ...
Em produção eu utilizo também uma chave para filtrar os
replicated_log, o que reduziria um pouco este número ( < 718309 ) ...
Estava pensando em colocar mais uma coluna (num_repl) em tzr_log, que
seria incrementada a cada registro inserido em replicated_log e assim
poderia adicionar mais uma condição ao select para tentar diminuir o
SCAN (num_repl < (select SUM(oid) FROM tzr_nodes) ...
Isto é uma boa prática ?? O que sugerem ??


> Pois assim ele irá efetuar seqScan nas duas tabelas ... e só depois
> aplicar o filtro ...

        Mas pense bem, é um problema difícil.  Você tem de ver quem existe numa
e não existe na outra; ou seja, você dificultou muito a seletividade,
caso em que vale a pena percorrer toda a relação.  Em outros termos,
como resolver a consulta sem percorrer ao menos uma relação?
Concordo ..Mas existe como modelar de outra forma ??
Tenho uma tabela de nós (tzr_nodes), outra de log (tzr_log) e outra de
logs replicados (tzr_replicated_log)...
Quando eu insiro, altero ou deleto um registro insiro este na tabela
de logs e replico este para o(s) nós que estão na tabela de nós e
insiro um registro em logs replicados com o id do log e o id do nó
para cada replicação que é efetuada com sucesso ...


        O melhor dos mundos seria, por exemplo, percorrer a tzr_log e, a partir
de seu índice, o índice da tzr_replicated_log, evitando a tabela
tzr_replicated_log em si.

Existe como implementar isso ?

        Aliás, teu modelo parece estranho.  Como é que pessoas estão em tzr_log
e telefones em tzr_replicated_log?
São apenas exemplos ... O EXPLAIN é de um modelo real (LOGS).

Att:
Thiago Risso
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a