Pergunta

Estou tentando fazer com que o recurso de pesquisa de texto completo do postgres funcione.

Tenho duas tabelas, uma que criei apenas para teste e a que desejo poder pesquisar:

Tabela de teste:

webarchive=# \d test_sites
                            Table "public.test_sites"
   Column    |   Type   |                        Modifiers
-------------+----------+---------------------------------------------------------
 id          | integer  | not null default nextval('test_sites_id_seq'::regclass)
 content     | text     |
 tsv_content | tsvector |
Indexes:
    "test_sites_pkey" PRIMARY KEY, btree (id)
    "idx_test_web_pages_content" gin (tsv_content)
Triggers:
    web_pages_testing_content_change_trigger AFTER INSERT OR UPDATE ON test_sites FOR EACH ROW EXECUTE PROCEDURE web_pages_testing_content_update_func()

Mesa "real":

webarchive=# \d web_pages
                                      Table "public.web_pages"
    Column    |            Type             |                       Modifiers
--------------+-----------------------------+--------------------------------------------------------
 id           | integer                     | not null default nextval('web_pages_id_seq'::regclass)
 state        | dlstate_enum                | not null
 errno        | integer                     |
 url          | text                        | not null
 starturl     | text                        | not null
 netloc       | text                        | not null
 file         | integer                     |
 priority     | integer                     | not null
 distance     | integer                     | not null
 is_text      | boolean                     |
 limit_netloc | boolean                     |
 title        | citext                      |
 mimetype     | text                        |
 type         | itemtype_enum               |
 raw_content  | text                        |
 content      | text                        |
 fetchtime    | timestamp without time zone |
 addtime      | timestamp without time zone |
 tsv_content  | tsvector                    |
Indexes:
    "web_pages_pkey" PRIMARY KEY, btree (id)
    "ix_web_pages_url" UNIQUE, btree (url)
    "idx_web_pages_content" gin (tsv_content)
    "idx_web_pages_title" gin (to_tsvector('english'::regconfig, title::text))
    "ix_web_pages_distance" btree (distance)
    "ix_web_pages_distance_filtered" btree (priority) WHERE state = 'new'::dlstate_enum AND distance < 1000000
    "ix_web_pages_priority" btree (priority)
    "ix_web_pages_type" btree (type)
    "ix_web_pages_url_ops" btree (url text_pattern_ops)
Foreign-key constraints:
    "web_pages_file_fkey" FOREIGN KEY (file) REFERENCES web_files(id)
Triggers:
    web_pages_content_change_trigger AFTER INSERT OR UPDATE ON web_pages FOR EACH ROW EXECUTE PROCEDURE web_pages_content_update_func()

Pedaços extras à parte, ambos têm um content coluna e um tsv_content coluna com um gin() indexe nele.Existe um gatilho que atualiza o tsv_content coluna toda vez que o content coluna é modificada.

Observe que o outro gin índice funciona bem e, na verdade, inicialmente tive um gin (to_tsvector('english'::regconfig, content::text)) índice na coluna de conteúdo também, em vez da segunda coluna, mas depois de esperar que esse índice fosse reconstruído algumas vezes nos testes, decidi usar uma coluna separada para pré-armazenar os valores do tsvector.

A execução de uma consulta na tabela de teste usa o índice como eu esperaria:

webarchive=# EXPLAIN ANALYZE SELECT
    test_sites.id,
    test_sites.content,
    ts_rank_cd(test_sites.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
    test_sites
WHERE
    test_sites.tsv_content @@ to_tsquery($$testing$$);
                                                              QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on test_sites  (cost=16.45..114.96 rows=25 width=669) (actual time=0.175..3.720 rows=143 loops=1)
   Recheck Cond: (tsv_content @@ to_tsquery('testing'::text))
   Heap Blocks: exact=117
   ->  Bitmap Index Scan on idx_test_web_pages_content  (cost=0.00..16.44 rows=25 width=0) (actual time=0.109..0.109 rows=143 loops=1)
         Index Cond: (tsv_content @@ to_tsquery('testing'::text))
 Planning time: 0.414 ms
 Execution time: 3.800 ms
(7 rows)

No entanto, o exatamente o mesmo consulta na tabela real nunca parece resultar em nada mas uma varredura sequencial simples e antiga:

webarchive=# EXPLAIN ANALYZE SELECT
       web_pages.id,
       web_pages.content,
       ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
   FROM
       web_pages
   WHERE
       web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                       QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
 Seq Scan on web_pages  (cost=0.00..4406819.80 rows=19751 width=505) (actual time=0.343..142325.954 rows=134949 loops=1)
   Filter: (tsv_content @@ to_tsquery('testing'::text))
   Rows Removed by Filter: 12764373
 Planning time: 0.436 ms
 Execution time: 142341.489 ms
(5 rows)

Aumentei minha memória de trabalho para 3 GB para ver se esse era o problema, e não é.

Além disso, deve-se observar que essas tabelas são bastante grandes - aproximadamente 150 GB de texto em 4 milhões de linhas (com 8 milhões de linhas adicionais onde content/tsv_content é NULL).

O test_sites tabela tem 1/1000 das linhas de web_pages, pois é um pouco proibitivo fazer experiências quando cada consulta leva vários minutos.


Estou usando o postgresql 9.5 (sim, eu mesmo compilei, queria ON CONFLICT).Não parece haver uma tag para isso ainda.

Eu li através do questões em aberto com 9,5, e não consigo ver isso sendo resultado de nenhum deles.


Recém-saído de uma reconstrução completa do índice, o problema ainda existe:

webarchive=# ANALYZE web_pages ;
ANALYZE
webarchive=# EXPLAIN ANALYZE SELECT
    web_pages.id,
    web_pages.content,
    ts_rank_cd(web_pages.tsv_content, to_tsquery($$testing$$)) AS ts_rank_cd_1
FROM
    web_pages
WHERE
    web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                              QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------
 Seq Scan on web_pages  (cost=10000000000.00..10005252343.30 rows=25109 width=561) (actual time=7.114..146444.168 rows=134949 loops=1)
   Filter: (tsv_content @@ to_tsquery('testing'::text))
   Rows Removed by Filter: 13137318
 Planning time: 0.521 ms
 Execution time: 146465.188 ms
(5 rows)

Observe que eu literalmente apenas ANALYZEed e seqscan está desabilitado.

Foi útil?

Solução

Bem, passei um pouco de tempo criando espaço extra no disco com o banco de dados, movendo alguns outros bancos de dados para outro SSD.

Eu então corri VACUUM ANALYZE em todo o banco de dados, e agora aparentemente percebi que tenho o index.

Eu já havia analisado e aspirado só esta mesa, mas aparentemente fez diferença fazê-lo em geral e não em uma tabela específica.Vai saber.

webarchive=# EXPLAIN ANALYZE SELECT
    web_pages.id,
    web_pages.content
FROM
    web_pages
WHERE
    web_pages.tsv_content @@ to_tsquery($$testing$$);
                                                                 QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on web_pages  (cost=1185.79..93687.30 rows=23941 width=189) (actual time=41.448..152.108 rows=134949 loops=1)
   Recheck Cond: (tsv_content @@ to_tsquery('testing'::text))
   Heap Blocks: exact=105166
   ->  Bitmap Index Scan on idx_web_pages_content  (cost=0.00..1179.81 rows=23941 width=0) (actual time=24.940..24.940 rows=134996 loops=1)
         Index Cond: (tsv_content @@ to_tsquery('testing'::text))
 Planning time: 0.452 ms
 Execution time: 154.942 ms
(7 rows)

Também aproveitei a oportunidade para fazer um VACUUM FULL; agora que tenho espaço suficiente para o processamento.Tive bastante mudança de linha na tabela enquanto fazia experiências durante o desenvolvimento e gostaria de tentar consolidar qualquer fragmentação de arquivo resultante disso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a dba.stackexchange
scroll top