CONSEGUI!! caramba, passei o dia todo nisso, mas finalmente consegui uma
alternativa viável (14s pra cruzar 200.000 x 400)

Agradeço a quem tentou ajudar! E aproveitando para responder:
EXISTS tinha um tempo de execução semelhante, e IN não era possível, pois
eu precisava buscar pela palavra inteira em qualquer lugar da string do
nome do produto.

Segue minha solução:

utilizei query de Full Text Search (@@) aliado a um dicionário 'dummy'.

ALTER TEXT SEARCH DICTIONARY simple(dummy);
ALTER TEXT SEARCH CONFIGURATION portuguese ALTER MAPPING FOR asciiword
 WITH simple;
com isso, a normalização do to_tsvector() e plainto_tsquery() ficam
'literais'.

na tabela products, criei uma coluna com indice 'tsvector_name' (tsvector),
rodando após a seguinte query:

UPDATE
   products
SET
   tsvector_name = to_tsvector(NAME)

e na tabela bad_words, fiz o mesmo, criando a coluna com indice
'tsquery_word' (tsquery) e rodando:

UPDATE
   bad_words
SET
   tsquery_word = plainto_tsquery('simple', word);

no final das contas, a query de busca final ficou:

  SELECT
     p.id,
     p.name,
     bw.*
  FROM
     products p
     LEFT JOIN bad_words bw ON *p.tsvector_name @@ bw.tsquery_word*
  WHERE
     bw.id IS NULL

e tá resolvido! =)




Em 28 de novembro de 2013 15:52, Douglas Fabiano Specht <
[email protected]> escreveu:

>
>
>
> Em 28 de novembro de 2013 15:24, Douglas Fabiano Specht <
> [email protected]> escreveu:
>
>
>>
>>
>> Em 28 de novembro de 2013 14:00, Pedro Cavalheiro 
>> <[email protected]>escreveu:
>>
>>> Boa tarde!
>>>
>>> Estou com um problema de performance em uma query, talvez alguém possa
>>> me ajudar!
>>>
>>> Situação:
>>>
>>> Postgres 9.1
>>> Tabela produtos (id, nome)
>>> Tabela bad_words (id, word)
>>>
>>> Preciso basicamente selecionar todos os registros de products, removendo
>>> os produtos cujo nome possui alguma palavra listada na tabela bad_words.
>>>
>>> Uma query para realizar isso, não é complexa... Daria pra fazer assim:
>>>
>>> SELECT
>>>    p.id,
>>>    p.name
>>> FROM
>>>    products p
>>>    LEFT JOIN bad_words bw ON p.name ~* bw.word
>>> WHERE
>>>    bw.id IS NULL
>>>
>>> Acredito que meu problema seja no número de cruzamentos realizados.
>>> Minha tabela de produtos, atualmente está com 200.000 registros, e a
>>> previsão é aumentar até 7.000.000 nos próximos meses. A tabela bad_words
>>> atualmente possui em torno de 400 registros.
>>>
>>> Rodando a consulta acima, o processamento leva em torno de 20 minutos
>>> (Intel i5 2.9ghz, 8gb ram, hd 7200rpm), inviável para a aplicação...
>>>
>>> Sei que milagres não existem, mas acredito que haja algum modo de
>>> indexar os valores envolvidos nesta consulta, ou melhorar a query, com a
>>> finalidade de diminuir o tempo total. Alguém tem alguma ideia?
>>>
>>> Agradeço pela ajuda!
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> pgbr-geral mailing list
>>> [email protected]
>>> https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral
>>>
>>>
>> ola..
>> amigo, poderia postar um explain e a ddl das tabelas?
>> tentou utilizar um in ou exists?
>>
>>
>> --
>>
>> Douglas Fabiano Specht
>>
>
> Pedro
> criei as duas tabelas aqui e veja a diferença no explain
>
> SELECT
>    p.id,
>    p.name
> FROM
>    products p
>    LEFT JOIN bad_words bw ON p.name  ~*bw.word
> WHERE
>    bw.id IS NULL
>
> explain:
> "Nested Loop Left Join  (cost=0.00..72167266.22 rows=1 width=37)"
> "  Join Filter: ((p.name)::text ~* (bw.word)::text)"
> "  Filter: (bw.id IS NULL)"
> "  ->  Seq Scan on products p  (cost=0.00..4496.25 rows=245225 width=37)"
> "  ->  Materialize  (cost=0.00..458.27 rows=19618 width=37)"
> "        ->  Seq Scan on bad_words bw  (cost=0.00..360.18 rows=19618
> width=37)"
>
>
> mudei o select para um in(nao sei se essa a sua ideia)
>
>    SELECT
>    p.id,
>    p.name
> FROM
>    products p
> WHERE
>   p.name in(select word from bad_words where id IS NUL)
>
> explain:
> "Hash Semi Join  (cost=605.40..10006.16 rows=245225 width=37)"
> "  Hash Cond: ((p.name)::text = (bad_words.word)::text)"
> "  ->  Seq Scan on products p  (cost=0.00..4496.25 rows=245225 width=37)"
> "  ->  Hash  (cost=360.18..360.18 rows=19618 width=33)"
> "        ->  Seq Scan on bad_words  (cost=0.00..360.18 rows=19618
> width=33)"
>
>
>
>
> Veja que a opção 2 o custo é bem menor, veja se nao pode utilizar ela..
>
> --
>
> Douglas Fabiano Specht
>
> _______________________________________________
> pgbr-geral mailing list
> [email protected]
> https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral
>
>
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a