乱序写入导致的索引膨胀(B-tree, GIN, GiST皆如此)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
简介:

标签

PostgreSQL , 索引分裂 , 乱序写入


背景

有些场景,用户会发现重建索引,索引比原来更小。

通常这种情况是索引字段乱序写入,导致索引频繁分裂,使得索引页并不是百分百填满。膨胀使然。

B-Tree索引

由于索引页中的数据是有序的,因此在乱序写入时,索引页可能出现分裂,分裂多了,空洞就会多起来(一页里面没有填满)。

例子

1、先建索引,乱序写入。

postgres=# create table t_idx_split(id int);  
CREATE TABLE  
postgres=# create index idx_t_idx_split on t_idx_split (id);  
CREATE INDEX  
postgres=# insert into t_idx_split select random()*10000000 from generate_series(1,10000000);  
INSERT 0 10000000  
postgres=# \di+ t_idx_sp  
  
postgres=# \di+ idx_t_idx_split   
                                List of relations  
 Schema |      Name       | Type  |  Owner   |    Table    |  Size  | Description   
--------+-----------------+-------+----------+-------------+--------+-------------  
 public | idx_t_idx_split | index | postgres | t_idx_split | 280 MB |   
(1 row)  

2、先建索引,顺序写入。

postgres=# truncate t_idx_split ;  
TRUNCATE TABLE  
postgres=# \di+ idx_t_idx_split   
                                  List of relations  
 Schema |      Name       | Type  |  Owner   |    Table    |    Size    | Description   
--------+-----------------+-------+----------+-------------+------------+-------------  
 public | idx_t_idx_split | index | postgres | t_idx_split | 8192 bytes |   
(1 row)  
  
postgres=# insert into t_idx_split select generate_series(1,10000000);  
INSERT 0 10000000  
postgres=# \di+ idx_t_idx_split   
                                List of relations  
 Schema |      Name       | Type  |  Owner   |    Table    |  Size  | Description   
--------+-----------------+-------+----------+-------------+--------+-------------  
 public | idx_t_idx_split | index | postgres | t_idx_split | 214 MB |   
(1 row)  

3、先写入,后建索引。

postgres=# drop index idx_t_idx_split ;  
DROP INDEX  
postgres=# create index idx_t_idx_split on t_idx_split (id);  
CREATE INDEX  
postgres=# \di+ idx_t_idx_split   
                                List of relations  
 Schema |      Name       | Type  |  Owner   |    Table    |  Size  | Description   
--------+-----------------+-------+----------+-------------+--------+-------------  
 public | idx_t_idx_split | index | postgres | t_idx_split | 214 MB |   
(1 row)  

很显然,顺序写入时,索引大小和后建索引大小一致,没有出现膨胀。

GIN索引

GIN索引也是树结构,也有膨胀的可能。

对于gin索引,实际上膨胀现象更加的明显,因为通常GIN是对多值类型的索引,而多值类型,通常输入的顺序更加无法保证。

GIN主树索引页会膨胀较厉害。

GiST和SP-GiST索引

同样存在这个现象,当写入的空间数据BOUND BOX是空间无序写入的,那么就会导致膨胀。

重建索引,可以收缩膨胀

建议并行建索引,防止堵塞DML

使用CONCURRENTLY关键字,并行创建索引,不会堵塞DML,但是创建索引的时间比正常创建索引的时间会略长。

Command:     CREATE INDEX
Description: define a new index
Syntax:
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ]
    ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
    [ WITH ( storage_parameter = value [, ... ] ) ]
    [ TABLESPACE tablespace_name ]
    [ WHERE predicate ]
相关文章
|
3天前
|
JSON 自然语言处理 数据格式
5.索引原理
5.索引原理
|
3天前
|
存储 算法 关系型数据库
MySQL索引 索引数据结构B+Tree、分类及使用、回表查询
MySQL索引 索引数据结构B+Tree、分类及使用、回表查询
110 0
|
10月前
|
存储 缓存 索引
PG13 B-tree索引去重
PG13 B-tree索引去重
57 0
|
存储 数据库 索引
B-Tree索引是干什么的?底层原理是什么?
B-Tree索引是干什么的?底层原理是什么?
110 0
|
存储 缓存 算法
倒排索引:ES倒排索引底层原理及FST算法的实现过程(二)
倒排索引:ES倒排索引底层原理及FST算法的实现过程(二)
倒排索引:ES倒排索引底层原理及FST算法的实现过程(二)
|
存储 自然语言处理 算法
倒排索引:ES倒排索引底层原理及FST算法的实现过程(一)
倒排索引:ES倒排索引底层原理及FST算法的实现过程
倒排索引:ES倒排索引底层原理及FST算法的实现过程(一)
|
存储 SQL 算法
FAQ系列 | B+树索引和哈希索引的区别
FAQ系列 | B+树索引和哈希索引的区别
163 0
FAQ系列 | B+树索引和哈希索引的区别
|
存储 关系型数据库 索引
Hash索引和B+树索引有什么区别或者说优劣势
Hash索引和B+树索引有什么区别或者说优劣势
403 0
|
存储 SQL 关系型数据库
索引到底能提升多少查询效率?何时该使用索引?一文快速搞懂数据库索引及合理使用它
索引到底能提升多少查询效率?何时该使用索引?一文快速搞懂数据库索引及合理使用它
459 0
索引到底能提升多少查询效率?何时该使用索引?一文快速搞懂数据库索引及合理使用它
|
存储 SQL 关系型数据库
InnoDB B-TREE 索引怎么定位一条记录
本文以 WHERE 条件能够命中索引为前提,介绍查询操作定位 WHERE 条件扫描区间的第一条记录。
InnoDB B-TREE 索引怎么定位一条记录