J'ai une grande table entities
avec environ 15 millions d'enregistrements. Je veux trouver les 5 premières lignes correspondant à «hockey» dans leur name
.
J'ai un index de texte intégral sur name
, qui est utilisé:gin_ix_entity_full_text_search_name
Requete:
SELECT "entities".*,
ts_rank(to_tsvector('english', "entities"."name"::text),
to_tsquery('english', 'hockey'::text)) AS "rank0.48661998202865475"
FROM "entities"
WHERE "entities"."place" = 'f'
AND (to_tsvector('english', "entities"."name"::text) @@ to_tsquery('english', 'hockey'::text))
ORDER BY "rank0.48661998202865475" DESC LIMIT 5
Durée 25,623 ms
Expliquez le plan 1 Limite (coût = 12666.89..12666.89 lignes = 5 largeur = 3116) 2 -> Trier (coût = 12666.89..12670.18 lignes = 6571 largeur = 3116) 3 Clé de tri: (ts_rank (to_tsvector ('english' :: regconfig, (name) :: text), '' 'hockey' '' :: tsquery)) 4 -> Bitmap Heap Scan sur les entités (coût = 124.06..12645.06 lignes = 6571 largeur = 3116) 5 Vérifiez à nouveau Cond: (to_tsvector ('english' :: regconfig, (name) :: text) @@ '' 'hockey' '' :: tsquery) 6 Filtre: (PAS placé) 7 -> Scan d'index bitmap sur gin_ix_entity_full_text_search_name (coût = 0,00..123,74 lignes = 6625 largeur = 0) 8 Index Cond: (to_tsvector ('english' :: regconfig, (name) :: text) @@ '' 'hockey' '' :: tsquery)
Je ne comprends pas pourquoi il vérifie la condition d'index deux fois. (Recherchez les étapes 4 et 7 du plan). Est-ce à cause de ma condition booléenne ( not place
)? Si oui, dois-je l'ajouter à mon index pour obtenir une requête très rapide? Ou la condition de tri la ralentit-elle?
EXPLAIN ANALYZE
production:
Limite (coût = 4447.28..4447.29 lignes = 5 largeur = 3116) (temps réel = 18509.274..18509.282 lignes = 5 boucles = 1) -> Trier (coût = 4447.28..4448.41 lignes = 2248 largeur = 3116) (temps réel = 18509.271..18509.273 lignes = 5 boucles = 1) Clé de tri: (ts_rank (to_tsvector ('english' :: regconfig, (name) :: text), '' 'test' '' :: tsquery)) Méthode de tri: top-N heapsort Mémoire: 19 Ko -> Bitmap Heap Scan sur les entités (coût = 43,31..4439,82 lignes = 2248 largeur = 3116) (temps réel = 119,003..18491,408 lignes = 2533 boucles = 1) Vérifiez à nouveau Cond: (to_tsvector ('english' :: regconfig, (name) :: text) @@ '' 'test' '' :: tsquery) Filtre: (PAS placer) -> Bitmap Index Scan sur gin_ix_entity_full_text_search_name (coût = 0,00..43,20 lignes = 2266 largeur = 0) (temps réel = 74,093..74,093 lignes = 2593 boucles = 1) Index Cond: (to_tsvector ('english' :: regconfig, (name) :: text) @@ '' 'test' '' :: tsquery) Durée totale: 18509,381 ms
Voici mes paramètres DB. Il est hébergé par Heroku, sur les services Amazon. Ils le décrivent comme ayant 1,7 Go de RAM, 1 unité de traitement et une base de données de 1 To maximum.
nom | paramètre actuel ------------------------------ + ------------------- -------------------------------------------------- ------------------------------------ version | PostgreSQL 9.0.7 sur i486-pc-linux-gnu, compilé par GCC gcc-4.4.real (Ubuntu 4.4.3-4ubuntu5) 4.4.3, 32 bits archive_command | test -f /etc/postgresql/9.0/main/wal-ed/ARCHIVING_OFF || envdir /etc/postgresql/9.0/resource29857_heroku_com/wal-ed/env wal-e wal-push% p archive_mode | sur archive_timeout | 1 minute checkpoint_completion_target | 0,7 checkpoint_segments | 40 client_min_messages | remarquer cpu_index_tuple_cost | 0,001 cpu_operator_cost | 0,0005 cpu_tuple_cost | 0,003 effective_cache_size | 1530000kB hot_standby | sur lc_collate | en_US.UTF-8 lc_ctype | en_US.UTF-8 listen_addresses | * log_checkpoints | sur log_destination | syslog log_line_prefix | % u [JAUNE] log_min_duration_statement | 50ms log_min_messages | remarquer logging_collector | sur maintenance_work_mem | 64 Mo max_connections | 500 max_prepared_transactions | 500 max_stack_depth | 2 Mo max_standby_archive_delay | -1 max_standby_streaming_delay | -1 max_wal_senders | dix port | random_page_cost | 2 encodage_serveur | UTF8 shared_buffers | 415MB ssl | sur syslog_ident | resource29857_heroku_com TimeZone | UTC wal_buffers | 8 Mo wal_keep_segments | 127 wal_level | pose chaude work_mem | 100 Mo (39 rangées)
ÉDITER
On dirait que ORDER BY
c'est la partie lente:
d6ifslbf0ugpu=> EXPLAIN ANALYZE SELECT "entities"."name",
ts_rank(to_tsvector('english', "entities"."name"::text),
to_tsquery('english', 'banana'::text)) AS "rank0.48661998202865475"
FROM "entities"
WHERE (to_tsvector('english', "entities"."name"::text) @@ to_tsquery('english', 'banana'::text))
LIMIT 5;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=43.31..53.07 rows=5 width=24) (actual time=76.583..103.623 rows=5 loops=1)
-> Bitmap Heap Scan on entities (cost=43.31..4467.60 rows=2266 width=24) (actual time=76.581..103.613 rows=5 loops=1)
Recheck Cond: (to_tsvector('english'::regconfig, (name)::text) @@ '''banana'''::tsquery)
-> Bitmap Index Scan on gin_ix_entity_full_text_search_name (cost=0.00..43.20 rows=2266 width=0) (actual time=53.592..53.592 rows=1495 loops=1)
Index Cond: (to_tsvector('english'::regconfig, (name)::text) @@ '''banana'''::tsquery)
Total runtime: 103.680 ms
Contre. avec ORDER BY
:
d6ifslbf0ugpu=> EXPLAIN ANALYZE SELECT "entities"."name",
ts_rank(to_tsvector('english', "entities"."name"::text),
to_tsquery('english', 'banana'::text)) AS "rank0.48661998202865475"
FROM "entities"
WHERE (to_tsvector('english', "entities"."name"::text) @@ to_tsquery('english', 'banana'::text))
ORDER BY "rank0.48661998202865475" DESC
LIMIT 5;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=4475.12..4475.13 rows=5 width=24) (actual time=15013.735..15013.741 rows=5 loops=1)
-> Sort (cost=4475.12..4476.26 rows=2266 width=24) (actual time=15013.732..15013.735 rows=5 loops=1)
Sort Key: (ts_rank(to_tsvector('english'::regconfig, (name)::text), '''banana'''::tsquery))
Sort Method: top-N heapsort Memory: 17kB
-> Bitmap Heap Scan on entities (cost=43.31..4467.60 rows=2266 width=24) (actual time=0.872..15006.763 rows=1495 loops=1)
Recheck Cond: (to_tsvector('english'::regconfig, (name)::text) @@ '''banana'''::tsquery)
-> Bitmap Index Scan on gin_ix_entity_full_text_search_name (cost=0.00..43.20 rows=2266 width=0) (actual time=0.549..0.549 rows=1495 loops=1)
Index Cond: (to_tsvector('english'::regconfig, (name)::text) @@ '''banana'''::tsquery)
Total runtime: 15013.805 ms
Mais je ne comprends toujours pas pourquoi c'est plus lent. On dirait qu'il récupère la même quantité de lignes à partir de Bitmap Heap Scan, mais cela prend beaucoup plus de temps?