乱序写入导致的索引膨胀(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 ]
gin-gonic是一个轻量级的Go语言Web框架,它被广泛用于构建高性能的Web应用程序。虽然它被认为是一个相对安全的框架,但没有一个完全免受安全漏洞的框架。下面我将介绍一些可能的gin-gonic gin安全漏洞,并提供相应的解决方案。 1. 跨站脚本攻击(XSS):攻击者通过注入恶意脚本代码来欺骗用户或窃取用户的敏感信息。为了防止XSS攻击,可以使用gin-gonic的SecureJSON中间件来自动转义输出,确保提交的数据不会被解释为HTML标签。 2. 跨站请求伪造(CSRF):攻击者通过伪造合法用户的请求,在用户毫不知情的情况下执行恶意操作。为了防止CSRF攻击,可以在每个表单中添加一个随机生成的令牌,并在请求中进行验证。 3. 敏感数据泄露:在处理敏感信息时,比如用户的密码或信用卡信息,应该尽量避免将其存储为明文。可以使用加密算法对这些敏感数据进行加密存储,并确保存储和传输过程中的数据安全。 4. 不安全的身份认证和授权:如果身份认证和授权不严谨,攻击者可能会绕过这些机制获取非法访问权限。使用合适的身份验证和授权机制,比如JWT(JSON Web Tokens)或OAuth,以确保只有授权用户能够访问受限资源。 5. SQL注入:如果应用程序没有正确过滤或转义用户输入,攻击者可以通过注入恶意SQL语句来执行未经授权的数据库操作。使用参数化查询或ORM(对象关系映射)框架来处理数据库查询,确保用户输入的数据被正确地转义。 总之,虽然gin-gonic gin是一个相对安全的框架,但在开发过程中仍然需要注意潜在的安全漏洞,并采取适当的措施来预防和修复这些漏洞。同时,及时更新和维护框架版本也是保证安全性的重要一环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值