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

简介:

标签

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月前
|
传感器 人工智能 监控
医院不良事件管理系统:PDCA持续改进,形成事件的整改闭环管理
医院安全事件管理系统通过全流程闭环管理、多维度分析与RCA根因分析,助力上报与处理高效协同,支持智能流转、风险预警与持续改进,提升医疗质量与患者安全。
465 5
|
Ubuntu Linux
Linux:查看服务器信息,CPU、内存、系统版本、内核版本等
Linux:查看服务器信息,CPU、内存、系统版本、内核版本等
7133 0
Linux:查看服务器信息,CPU、内存、系统版本、内核版本等
|
自然语言处理 JavaScript 前端开发
Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(1)
Vue3 + Vite + TypeScript + Element-Plus:从零到一构建企业级后台管理系统(前后端开源)(1)
|
8月前
|
JSON 前端开发 Java
深入理解 Spring Boot 中日期时间格式化:@DateTimeFormat 与 @JsonFormat 完整实践
在 Spring Boot 开发中,处理前后端日期交互是一个常见问题。本文通过 **@DateTimeFormat** 和 **@JsonFormat** 两个注解,详细讲解了如何解析前端传来的日期字符串以及以指定格式返回日期数据。文章从实际案例出发,结合代码演示两者的使用场景与注意事项,解决解析失败、时区偏差等问题,并提供全局配置与局部注解的实践经验。帮助开发者高效应对日期时间格式化需求,提升开发效率。
2479 2
|
存储 Oracle 关系型数据库
【实操】单表数据量 200 GB,PostgreSQL 怎么应对??
【实操】单表数据量 200 GB,PostgreSQL 怎么应对??
606 1
|
JSON 数据格式
解决报错TypeError: Converting circular structure to JSON --> starting at object with constructor
解决报错TypeError: Converting circular structure to JSON --> starting at object with constructor
|
Shell Windows
电脑文件打开缓慢、右键卡顿解决方案
本文汇总了几种解决电脑文件打开缓慢和右键点击文件夹卡顿问题的方案,包括重启资源管理器、修改注册表中的Shell Extensions、以及设置在单独的进程中打开文件夹窗口。
|
数据安全/隐私保护
CTF — 压缩包密码爆破
CTF — 压缩包密码爆破
1527 0
|
存储 JSON 前端开发
【Java】用@JsonFormat(pattern = “yyyy-MM-dd“)注解,出生日期竟然年轻了一天
在实际项目中,使用 `@JsonFormat(pattern = "yyyy-MM-dd")` 注解导致出生日期少了一天的问题,根源在于夏令时的影响。本文详细解析了夏令时的概念、`@JsonFormat` 注解的使用方法,并提供了三种解决方案:在注解中添加 `timezone = GMT+8`、修改 JVM 参数 `-Duser.timezone=GMT+08`,以及使用 `timezone = Asia/Shanghai
1667 0
【Java】用@JsonFormat(pattern = “yyyy-MM-dd“)注解,出生日期竟然年轻了一天