PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 25/08/2023 18:30:45

Index BRIN

Bonjour,

Il y a quelque chose qui me laisse perplexe, c'est la non utilisation de l'index BRIN sur un max() :

aegir=# select version();
                                                               version                                                                
--------------------------------------------------------------------------------------------------------------------------------------
 PostgreSQL 14.9 (Ubuntu 14.9-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
(1 row)
aegir=# create table example (id bigint);
CREATE TABLE
aegir=# create index brin_example on example  using brin(id);
CREATE INDEX
aegir=# insert into example ( select generate_series(1,1000000));
INSERT 0 1000000
aegir=# select pg_size_pretty(pg_relation_size('example'));
 pg_size_pretty 
----------------
 35 MB
(1 row)

aegir=# select pg_size_pretty(pg_relation_size('brin_example'));
 pg_size_pretty 
----------------
 24 kB
(1 row)
aegir=# explain (analyze, verbose) select max(id) from example;
                                                                   QUERY PLAN                                                                    
-------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=10633.55..10633.56 rows=1 width=8) (actual time=80.798..90.351 rows=1 loops=1)
   Output: max(id)
   ->  Gather  (cost=10633.33..10633.54 rows=2 width=8) (actual time=80.732..90.344 rows=3 loops=1)
         Output: (PARTIAL max(id))
         Workers Planned: 2
         Workers Launched: 2
         ->  Partial Aggregate  (cost=9633.33..9633.34 rows=1 width=8) (actual time=55.675..55.676 rows=1 loops=3)
               Output: PARTIAL max(id)
               Worker 0:  actual time=43.249..43.250 rows=1 loops=1
               Worker 1:  actual time=43.237..43.238 rows=1 loops=1
               ->  Parallel Seq Scan on public.example  (cost=0.00..8591.67 rows=416667 width=8) (actual time=0.009..26.193 rows=333333 loops=3)
                     Output: id
                     Worker 0:  actual time=0.011..20.722 rows=251488 loops=1
                     Worker 1:  actual time=0.011..20.815 rows=251764 loops=1
 Planning Time: 0.192 ms
 Execution Time: 90.382 ms
(16 rows)

Pourquoi diable le BRIN n'est pas utilisé ? Je pensais qu'il suffisait de faire le max de toutes les bornes supérieures pour avoir le max() non ?


Évidemment, avec un index btree, l'index est bien utilisé :

aegir=# create index bt_example on example(id);
CREATE INDEX
aegir=# explain (analyze, verbose) select max(id) from example;
                                                                           QUERY PLAN                                                                            
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.45..0.46 rows=1 width=8) (actual time=0.026..0.027 rows=1 loops=1)
   Output: $0
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.42..0.45 rows=1 width=8) (actual time=0.024..0.025 rows=1 loops=1)
           Output: example.id
           ->  Index Only Scan Backward using bt_example on public.example  (cost=0.42..28480.42 rows=1000000 width=8) (actual time=0.023..0.024 rows=1 loops=1)
                 Output: example.id
                 Index Cond: (example.id IS NOT NULL)
                 Heap Fetches: 0
 Planning Time: 0.165 ms
 Execution Time: 0.039 ms
(11 rows)

Il y a quelque chose qui m'échappe au sujet des BRIN ?

Hors ligne

#2 28/08/2023 20:29:22

pifor
Membre

Re : Index BRIN

D'après la discussion https://www.postgresql.org/message-id/1 … .pgh.pa.us, il s'agit d'une limite connue des index BRIIN.
Peut-être qu'il s'agit plus d'une limite du "query planner" ?


Pierre

Hors ligne

#3 29/08/2023 04:07:21

rjuju
Administrateur

Re : Index BRIN

Il s'agit plutôt d'une limitation générale dans l'infrastructure de postgres.  Pour l'instant, les seuls moyens de récupérer un min() ou max() sont:

- renvoyer les donneés triées dans l'ordre voulu et s'arrêter une fois une valeur trouvée
- lire toutes les données et conserver la valeur maximum trouvée


La première approche n'est intéressante que si on peut retourner les données triées dans l'ordre voulu, ce qui n'est le cas que pour un index btree.


Utiliser un index brin pour récupérer la valeur max sans lire toutes les données de la table serait théoriquement possible, mais nécessiterait de développer un nouveau mode d'exécution.  Comme discuté dans le thread pointé par pifor, le problème est également plus complexe qu'il ne parait car les valeurs min/max stockées dans l'index brin ne sont pas maintenues, et il n'y a aucune garanties que ces valeurs soient toujours visible, ou simplement visible par la requête en cours d'exécution.  Cela veut dire la nécessité d'avoir une approche récursive dans le cas où les ranges choisis ne contiennent aucune valeur supposées être présentes uniquement dans ceux-ci. Dans des cas extrêmes le temps d'exécution pourrait devenir bien pire que lire toutes les données séquentiellement (potentiellement avec des workers parallèles).  À noter qu'il n'y a pour l'instant aucune statistique qui pourrait aider à décider si ce type de parcours serait intéressant ou non.  Le cumul de tout ça explique probablement pourquoi personne n'est intéressé pour travailler sur le sujet.

Hors ligne

Pied de page des forums