乱序写入导致的索引膨胀(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 ]
时间: 2024-08-01 19:56:23

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

从难缠的模糊查询聊开 - PostgreSQL独门绝招之一 GIN , GiST , SP-GiST , RUM 索引原理与技术背景

标签 PostgreSQL , gist , sp-gist , gin , rum index , 模糊查询 , 搜索引擎 , token位置搜索 , pg_hint_plan , 自动优化 , 分词 , like '%xxx%' 背景 模糊查询,是一个需求量很大,同时也是一个对数据库来说非常难缠的需求. 对于前模糊(like '%xxx'),可以使用倒排B-TREE索引解决,对于后模糊(like 'xxx%'),可以使用B-TREE索引解决. B-TREE索引通常支持的查询包括 > , <

懒人促进社会进步 - 5种索引的原理和优化Case (btree,hash,gin,gist,brin)

标签 PostgreSQL , 多列聚合 , gin , btree , n_distinct , 选择性 , 如何选择索引方法(hash,btree,gin,gist,brin) , 如何优化索引 , 相关性 背景 在广告行业,精准营销是一个较热的话题,之前写过一个案例,如何使用PostgreSQL的array类型和GIN索引实时圈人的场景. <万亿级营销(圈人)迈入毫秒时代 - 万亿user_tags级实时推荐系统数据库设计> 使用以上方法,程序需要作出一些调整(当然,如果用户原本就是Po

《中国人工智能学会通讯》——4.34 数据包乱序

4.34 数据包乱序 在网络环境下,被传输的数据流经众多计算机和通信设备且路径不唯一,这必然会导致数据包的时序错乱问题.数据包乱序一般发生在具有路由.网关等中继环节的长时延 NCSs 中.由于路由器会根据网络的实际情况选择合适的网络途径传输数据,相同节点发送的数据包可能会经过不同的网络路径到达目标节点,另外数据包在中继环节的队列中等待的时间往往也不相同,因而造成数据包的时序错乱.在NCSs中,数据包的乱序又分为两种情况:一是在单包传输的情况下,由于每个数据包中的数据是完整的,此时的数据包的时序错

日志服务新功能发布(1)--支持保序写入和消费

日志服务在上周新上线的版本,支持数据的保序写入和消费,shard的split和merge, server端consumer group的原生支持(除去对mysql的依赖),数据自动同步至oss等一些列新功能.本文主要介绍数据的保序写入和消费的功能. LogStore & Shard 关系 每个LogStore对应一类日志,对于同一个LogStore下的数据,所有处理逻辑相同(索引方式.导入odps.oss等配置) 每个LogStore由一个或多个shard组成,用于支持数据写入水平扩展 每个sh

解决Android ListView异步加载图片乱序问题

在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不少人在网上搜索找到了相应的解决方案,但是真正深入理解这个问题出现的原因并对症解决的人恐怕还并不是很多.那么今天我们就来具体深入分析一

由乱序播放说开了去-数组的打乱算法Fisher–Yates Shuffle

之前用HTML5的Audio API写了个音乐频谱效果,再之后又加了个播放列表就成了个简单的播放器,其中弄了个功能是'Shuffle'也就是一般播放器都有的列表打乱功能,或者理解为随机播放. 但我觉得随机播放绝对要好实现些,用Math.random()产生一个介于1到歌曲数目之间的随机数便可,然后player.play(随机数). 而列表的打乱情况要不一样点,一是要呈现到界面,歌曲顺序要随机排,二是播放顺序不变,该哪是哪,只是该位置上的歌曲可能已经变成其他曲目了.抽象出来就是数组元素的重排,那么

使用乱序标签来控制HTML的输出效果

控制 在HTML的元素中,有一个比较特殊的元素form.我们用它来收集表单数据并提交给服务器,并且理论上说来它是没有任何的UI被呈现的.当然如果我们在body元素后紧跟一个form,这样一来似乎看不出来有什么UI呈现的问题,可是当form存在于别的元素之中时,就有问题了. 什么问题呢?看下面的示例,由于页面布局的需要,我需要控制页面的滚动条.我把body的滚动条隐藏掉,然后使用一个div元素来"自制"一个滚动条,html代码如下: <html> <head> &

Chrome谷歌浏览器中js代码Array.sort排序的bug乱序解决办法

[现象] 代码如下: var list = [{ n: "a", v: 1 }, { n: "b", v: 1 }, { n: "c", v: 1 }, { n: "d", v: 1 }, { n: "e", v: 1 }, { n: "f", v: 1 }, { n: "g", v: 1 }, { n: "h", v: 1 }, { n: &qu

C#简单实现List乱序

最近搞一个自动运行系统,需要实现大量的随机方法,其中就有随机排序List. 我记得在JDK里面的List有个 Collections.shuffle(list) 方法,可以直接进行列表乱序,结果在C#里面却没有发现相关的方法,很是头疼. 看了网上介绍的一些方法发现在效率上都很差,然后查看了一下MSDN,想起List还有个Insert方法,嘿嘿,灵机一动,搞出一个非常简单的东西,代码如下: 程序代码 Random random = new Random(); List<Content> newL