Introduction aux types d'index POSTGRESQL (PG) 6 et exemples d'utilisation

Dans l'optimisation des requêtes SQL de base de données, l'indexation est la méthode d'optimisation la plus couramment utilisée. L'utilisation raisonnable des index peut grandement améliorer l'efficacité de l'interrogation de la base de données et tirer pleinement parti des ressources système. Dans une base de données, l'utilisation d'un index lorsque le taux de sélection des données est relativement faible peut améliorer les performances, mais si le taux de sélection des données est relativement élevé, l'index entraînera un coût de lecture d'index supplémentaire et, en même temps, cela entraînera des problèmes de lecture aléatoire. , et les performances ne sont pas aussi bonnes que l'analyse séquentielle. Par conséquent, le type d'index présenté dans cet article ne peut être utilisé que pour les instructions SQL avec un taux de sélection de données relativement faible. C'est la prémisse du choix d'un index.

Postgresql supporte principalement six types d'index : BTREE, HASH, GiST, SP-GiSP, GIN, BRIN. Vous pouvez choisir un index approprié en fonction du scénario d'application réel. BTREE et HASH sont les index les plus couramment utilisés.

1. Indice BTREE :

CREATE INDEX utilise l'index BTREE par défaut, qui convient aux requêtes de comparaison et aux requêtes de plage sur des données stockées dans l'ordre. L'optimiseur de requête donnera la priorité à l'utilisation de l'index BTREE si l'une des opérations suivantes est impliquée :

1)<,<=,=,>,>=

2) Et des combinaisons de ces opérations, comme entre et, peuvent également utiliser BTREE.

3) IS NULL ou IS NOT NULL sur la colonne d'index peut également utiliser BTREE.

4) L'index BTREE peut également être utilisé pour les requêtes floues, mais uniquement lorsque le début de la chaîne est une constante, telle que name LIKE 'Jason%' ou name ~ '^Jason'. Mais le nom LIKE '%Jason' ne peut pas être utilisé.

5) L'opération d'agrégation Min/Max peut également utiliser l'index BTREE.

6) En fait, dans merge join and order by, le coût du tri peut être réduit en utilisant l'ordre de l'index BTREE.

exemple:

test=# create table t1 (id int,  info text);
CREATE TABLE
test=# insert into t1 values(generate_series(1,100000), md5(random()::text));
INSERT 0 100000
test=# \d t1
                 Table "public.t1"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 info   | text    |           |          |

test=# analyze t1;
ANALYZE
--不建立索引,默认使用顺序扫描
test=# explain select * from t1 where t1.id = 10007;
                      QUERY PLAN
------------------------------------------------------
 Seq Scan on t1  (cost=0.00..2084.00 rows=1 width=37)
   Filter: (id = 10007)
(2 rows)

test=# explain select * from t1 where t1.id >10007;
                        QUERY PLAN
----------------------------------------------------------
 Seq Scan on t1  (cost=0.00..2084.00 rows=90249 width=37)
   Filter: (id > 10007)
(2 rows)

test=# explain select * from t1 where t1.id > 10007 and t1.id < 12000;
                       QUERY PLAN
---------------------------------------------------------
 Seq Scan on t1  (cost=0.00..2334.00 rows=2042 width=37)
   Filter: ((id > 10007) AND (id < 12000))
(2 rows)
--建立BTREE索引
test=# create index on t1(id);
CREATE INDEX
test=# analyze t1;
ANALYZE
test=# explain select * from t1 where t1.id = 10007;
                             QUERY PLAN
---------------------------------------------------------------------
 Index Scan using t1_id_idx on t1  (cost=0.29..8.31 rows=1 width=37)
   Index Cond: (id = 10007)
(2 rows)
--下面例子中没有使用索引的原因是选择率太高,优化器会使用顺序扫描
test=# explain select * from t1 where t1.id >10007;
                        QUERY PLAN
----------------------------------------------------------
 Seq Scan on t1  (cost=0.00..2084.00 rows=90103 width=37)
   Filter: (id > 10007)
(2 rows)

test=# explain select * from t1 where t1.id > 10007 and t1.id < 12000;
                               QUERY PLAN
-------------------------------------------------------------------------
 Index Scan using t1_id_idx on t1  (cost=0.29..83.73 rows=1972 width=37)
   Index Cond: ((id > 10007) AND (id < 12000))
(2 rows)

test=# explain select * from t1 where t1.id >98765;
                               QUERY PLAN
-------------------------------------------------------------------------
 Index Scan using t1_id_idx on t1  (cost=0.29..51.31 rows=1201 width=37)
   Index Cond: (id > 98765)
(2 rows)

test=# \d t1
                 Table "public.t1"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 info   | text    |           |          |
Indexes:
    "t1_id_idx" btree (id)

test=# explain select * from t1 where t1.id between 10007 and 11000;
                               QUERY PLAN
------------------------------------------------------------------------
 Index Scan using t1_id_idx on t1  (cost=0.29..43.79 rows=975 width=37)
   Index Cond: ((id >= 10007) AND (id <= 11000))
(2 rows)

test=# explain select * from t1 where t1.id IS NULL;
                             QUERY PLAN
---------------------------------------------------------------------
 Index Scan using t1_id_idx on t1  (cost=0.29..4.31 rows=1 width=37)
   Index Cond: (id IS NULL)
(2 rows)

test=# create index on t1(info text_pattern_ops);
CREATE INDEX
test=# \d t1;
                 Table "public.t1"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 info   | text    |           |          |
Indexes:
    "t1_id_idx" btree (id)
    "t1_info_idx" btree (info text_pattern_ops)

test=# analyze t1;
ANALYZE
--模糊查询使用索引
test=# explain select * from t1 where t1.info like '0123%';
                               QUERY PLAN
------------------------------------------------------------------------
 Index Scan using t1_info_idx on t1  (cost=0.42..8.44 rows=10 width=37)
   Index Cond: ((info ~>=~ '0123'::text) AND (info ~<~ '0124'::text))
   Filter: (info ~~ '0123%'::text)
(3 rows)

test=# explain analyze select min(id) from t1;
                                                               QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.33..0.34 rows=1 width=4) (actual time=0.143..0.143 rows=1 loops=1)
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.29..0.33 rows=1 width=4) (actual time=0.114..0.116 rows=1 loops=1)
           ->  Index Only Scan using t1_id_idx on t1  (cost=0.29..3691.29 rows=100000 width=4) (actual time=0.107..0.107 rows=1 loops=1)
                 Index Cond: (id IS NOT NULL)
                 Heap Fetches: 1
 Planning Time: 0.531 ms
 Execution Time: 0.263 ms
(8 rows)

test=# explain analyze select max(id) from t1;
                                                                    QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=0.33..0.34 rows=1 width=4) (actual time=0.054..0.054 rows=1 loops=1)
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.29..0.33 rows=1 width=4) (actual time=0.043..0.044 rows=1 loops=1)
           ->  Index Only Scan Backward using t1_id_idx on t1  (cost=0.29..3691.29 rows=100000 width=4) (actual time=0.040..0.041 rows=1 loops=1)
                 Index Cond: (id IS NOT NULL)
                 Heap Fetches: 1
 Planning Time: 0.485 ms
 Execution Time: 0.128 ms
(8 rows)

test=#

2. Indice de hachage :

Il ne peut gérer qu'une simple comparaison d'égalité. Lorsque la colonne d'index implique une comparaison d'opérations égales, l'optimiseur envisage d'utiliser l'index de hachage. L'index de hachage consiste à rechercher et à localiser en comparant les valeurs de hachage. Si le degré de répétition des données de la colonne d'index de hachage est relativement élevé, de graves conflits de hachage sont susceptibles de se produire, ce qui réduit l'efficacité de la requête. Par conséquent, dans ce cas, l'index de hachage n'est pas adapté.

CREATE INDEX idx_name ON table_name USING HASH (column_name);

exemple:

test=# create table t2 (id int, info text);
CREATE TABLE
test=# insert into t2 values(generate_series(1,100000), md5(random()::text));
INSERT 0 100000
test=# create index on t2 using hash(id);
CREATE INDEX
test=# analyze t2;
ANALYZE
test=# \d t2;
                 Table "public.t2"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 info   | text    |           |          |
Indexes:
    "t2_id_idx" hash (id)

test=# explain select * from t2 where id = 10008;
                             QUERY PLAN
---------------------------------------------------------------------
 Index Scan using t2_id_idx on t2  (cost=0.00..8.02 rows=1 width=37)
   Index Cond: (id = 10008)
(2 rows)
--非等于操作不会用到hash索引
test=# explain select * from t2 where id < 10008;
                       QUERY PLAN
---------------------------------------------------------
 Seq Scan on t2  (cost=0.00..2084.00 rows=9826 width=37)
   Filter: (id < 10008)
(2 rows)

test=# explain select * from t2 where id is NULL;
                      QUERY PLAN
------------------------------------------------------
 Seq Scan on t2  (cost=0.00..1834.00 rows=1 width=37)
   Filter: (id IS NULL)
(2 rows)

test=#

3. Indice GiST

Il ne s'agit pas d'un type d'index indépendant, mais d'une architecture ou d'un modèle d'index et d'un arbre binaire équilibré. Applicable aux types de données multidimensionnelles et aux types de données de collecte, similaire à l'index Btree, également applicable à d'autres types de données. GiST peut être utilisé pour effectuer des recherches de position telles que contient, croise, gauche, droite, etc. Par rapport à l'index Btree, l'index multi-champ GiST utilisera le balayage d'index si un sous-ensemble du champ d'index est inclus dans la condition de requête, tandis que l'index Btree n'utilisera le balayage d'index que si la condition de requête contient le premier champ d'index. Les types d'opérateurs spécifiques à l'index GiST dépendent fortement de la stratégie d'indexation (classe d'opérateur). Comparé à l'index Btree, GiST prend beaucoup de temps pour créer l'index et prend beaucoup de place.

Dans l'exemple suivant, un index composite BTREE (a, b) est établi. S'il y a a ou a, b dans la condition SQL where, l'index composite peut être utilisé, mais s'il n'y a que b dans la condition where, la l'index ne peut pas être utilisé. Actuellement, GiST peut résoudre cette situation.

exemple:

test=# create table t3(a bigint, b timestamp without time zone,c varchar(64));
CREATE TABLE                                                             ^
test=# insert into t3 values(generate_series(1,100000), now()::timestamp, md5(random()::text));
INSERT 0 100000
test=# create index on t3(a, b);
CREATE INDEX
test=# analyze t3;
ANALYZE
test=# \d t3
                           Table "public.t3"
 Column |            Type             | Collation | Nullable | Default
--------+-----------------------------+-----------+----------+---------
 a      | bigint                      |           |          |
 b      | timestamp without time zone |           |          |
 c      | character varying(64)       |           |          |
Indexes:
    "t3_a_b_idx" btree (a, b)

test=# explain select * from t3 where a = 10000;
                              QUERY PLAN
----------------------------------------------------------------------
 Index Scan using t3_a_b_idx on t3  (cost=0.42..8.44 rows=1 width=49)
   Index Cond: (a = 10000)
(2 rows)

test=# explain select * from t3 where b = '2022-11-18 17:50:29.245683';
                                QUERY PLAN
---------------------------------------------------------------------------
 Seq Scan on t3  (cost=0.00..2281.00 rows=1 width=49)
   Filter: (b = '2022-11-18 17:50:29.245683'::timestamp without time zone)
(2 rows)

test=# create extension btree_gist;
CREATE EXTENSION
test=# create index idx_t3_gist on t3 using gist(a,b);
CREATE INDEX
test=# analyze t3;
ANALYZE
test=# explain select * from t3 where a = 10000;
                              QUERY PLAN
----------------------------------------------------------------------
 Index Scan using t3_a_b_idx on t3  (cost=0.42..8.44 rows=1 width=49)
   Index Cond: (a = 10000)
(2 rows)

test=# explain select * from t3 where b = '2022-11-18 17:50:29.245683';
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Index Scan using idx_t3_gist on t3  (cost=0.28..8.30 rows=1 width=49)
   Index Cond: (b = '2022-11-18 17:50:29.245683'::timestamp without time zone)
(2 rows)

test=# explain select * from t3 where a = '10000';
                              QUERY PLAN
-----------------------------------------------------------------------
 Index Scan using idx_t3_gist on t3  (cost=0.28..8.30 rows=1 width=49)
   Index Cond: (a = '10000'::bigint)
(2 rows)

test=# explain select * from t3 where a = '10000' or b = '2022-11-18 17:50:29.245683';
                                                 QUERY PLAN
------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t3  (cost=8.58..12.59 rows=1 width=49)
   Recheck Cond: ((a = '10000'::bigint) OR (b = '2022-11-18 17:50:29.245683'::timestamp without time zone))
   ->  BitmapOr  (cost=8.58..8.58 rows=1 width=0)
         ->  Bitmap Index Scan on idx_t3_gist  (cost=0.00..4.29 rows=1 width=0)
               Index Cond: (a = '10000'::bigint)
         ->  Bitmap Index Scan on idx_t3_gist  (cost=0.00..4.29 rows=1 width=0)
               Index Cond: (b = '2022-11-18 17:50:29.245683'::timestamp without time zone)
(7 rows)

test=# explain select * from t3 where a = '10000' and  b = '2022-11-18 17:50:29.245683';
                                                QUERY PLAN
-----------------------------------------------------------------------------------------------------------
 Index Scan using t3_a_b_idx on t3  (cost=0.42..6.19 rows=1 width=49)
   Index Cond: ((a = '10000'::bigint) AND (b = '2022-11-18 17:50:29.245683'::timestamp without time zone))
(2 rows)

test=#

4. Indice SP-GiST

Semblable à GiST, mais c'est un arbre déséquilibré qui prend en charge des données multidimensionnelles et massives, et divise l'espace en parties mutuellement disjointes. SP-GiST convient aux structures dont l'espace peut être partitionné de manière récursive en régions disjointes, y compris les arbres quaternaires, les arbres kD et les arbres radix.

5. Indice GIN

Index inversé, adapté aux données contenant plusieurs valeurs de composants, telles que les tableaux, la recherche de texte intégral, etc. Il est utilisé pour enregistrer une collection de paires clé-valeur et prend en charge les stratégies d'indexation définies par l'utilisateur. Différents opérateurs peuvent être utilisés pour différentes stratégies d'indexation.

Paire clé-valeur (Clé, liste de positions) : où Clé est une valeur de clé et liste de positions est une valeur de position contenant Clé. Par exemple ('Bob', '10:25 14:3 29:5') signifie que le mot clé 'Bob' existe à ces positions (tuple TID). Lorsque nous utilisons le mot clé 'Bob' pour interroger, nous localisons immédiatement ces trois tuples contenant le mot clé.

La méthode d'utilisation est la suivante :

test=# create table t4(id int, info text);
CREATE TABLE
test=# insert into t4 values(generate_series(1,10000), md5(random()::text));
INSERT 0 10000
test=# create index idx_t4_gin on t4 using gin(to_tsvector('english',info));
CREATE INDEX
test=# analyze t4;
ANALYZE
test=# \d t4
                 Table "public.t4"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 info   | text    |           |          |
Indexes:
    "idx_t4_gin" gin (to_tsvector('english'::regconfig, info))

test=# explain select * from t4 where to_tsvector('english', info) @@ plainto_tsquery( 'hello');
                                           QUERY PLAN
-------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t4  (cost=12.25..16.77 rows=1 width=37)
   Recheck Cond: (to_tsvector('english'::regconfig, info) @@ plainto_tsquery('hello'::text))
   ->  Bitmap Index Scan on idx_t4_gin  (cost=0.00..12.25 rows=1 width=0)
         Index Cond: (to_tsvector('english'::regconfig, info) @@ plainto_tsquery('hello'::text))
(4 rows)

6. Indice BRIN

Index de plage de blocs, qui regroupe les blocs de données sur le disque selon un certain nombre, et calcule la plage de valeurs de chaque groupe après regroupement. Lors de la recherche de données, ces plages de valeurs seront parcourues pour exclure les groupes qui ne se trouvent pas dans la plage. Les index BRIN conviennent au stockage des journaux de données en continu. Par exemple : pour des données insérées en fonction du temps, du fait que les données sont insérées en fonction du temps, les informations de plage enregistrées sur le bloc de données se chevaucheront rarement, et le nombre de blocs de données à comparer après filtrage d'index sera bien moindre ; à l'inverse, si les données se croisent sérieusement, lorsqu'aucun bloc de données ne peut être filtré à travers l'index, l'opération prendra plus de temps qu'une analyse complète de la table.

test=# create table t5(id int, name text);
CREATE TABLE
test=# insert into t5 values(generate_series(1,100000), md5(random()::text));
INSERT 0 100000
test=#  create index idx_t5_brin on t5 using brin(id);
CREATE INDEX
test=# analyze t5;
ANALYZE
test=# \d t5
                 Table "public.t5"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           |          |
 name   | text    |           |          |
Indexes:
    "idx_t5_brin" brin (id)

test=# explain select * from t5 where id > 98765;
                                  QUERY PLAN
-------------------------------------------------------------------------------
 Bitmap Heap Scan on t5  (cost=12.33..1024.91 rows=1199 width=37)
   Recheck Cond: (id > 98765)
   ->  Bitmap Index Scan on idx_t5_brin  (cost=0.00..12.03 rows=14286 width=0)
         Index Cond: (id > 98765)
(4 rows)

test=# explain analyze select * from t5 where id > 98765;
                                                         QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t5  (cost=12.33..1024.91 rows=1199 width=37) (actual time=2.033..2.408 rows=1235 loops=1)
   Recheck Cond: (id > 98765)
   Rows Removed by Index Recheck: 6605
   Heap Blocks: lossy=66
   ->  Bitmap Index Scan on idx_t5_brin  (cost=0.00..12.03 rows=14286 width=0) (actual time=0.043..0.043 rows=1280 loops=1)
         Index Cond: (id > 98765)
 Planning Time: 0.115 ms
 Execution Time: 2.545 ms
(8 rows)

test=#

Guess you like

Origin blog.csdn.net/helenbi/article/details/127927748