概述
一般当一个表膨胀时一般使用vacuum full或者cluster进行表重建,在这一过程中会加排他锁,导致该表无法进行读写,只有等整个过程完成后才可以进行正常使用。
pg_squeeze就是来解决这个问题的,它只会在最后切换filenode的过程中加锁,其他过程中是不影响读写的。
安装
下面说下安装pg_squeeze需要注意的地方:
1.先配置好PG_CONFIG就是命令pg_config的路径。
2.make 和 make install。
3.配置postgresql.conf的几个参数,因为这个要使用逻辑复制来实现增量重组的所以要配置
wal_level=logical; max_replication_slots=1(最少大于1);shared_preload_libraries='pg_squeeze'
4.create extension pg_squeeze。
使用
首先创建表,表中必须要有一个主键或者是唯一键。
postgres=# create table a(id int primary key);
CREATE TABLE
postgres=# insert into a select generate_series(1,2000000);
INSERT 0 2000000
安装完这个插件后,你会看到多了一些表和函数,我们重点说一下squeeze.tables这个表
postgres=# dt squeeze.
List of relations
Schema | Name | Type | Owner |
---|---|---|---|
squeeze | errors | table | postgres |
squeeze | log | table | postgres |
squeeze | tables | table | postgres |
squeeze | tables_internal | table | postgres |
squeeze | tasks | table | postgres |
(5 rows)
postgres=# d squeeze.tables
Table "squeeze.tables"
Column | Type | Modifiers
id | integer | not null default nextval('squeeze.tables_id_seq'::regcla
ss)
tabschema | name | not null
tabname | name | not null
clustering_index | name |
rel_tablespace | name |
ind_tablespaces | name[] |
task_interval | interval | not null default '01:00:00'::interval
first_check | timestamp with time zone | not null
free_space_extra | integer | not null default 50
min_size | real | not null default 8
vacuum_max_age | interval | not null default '01:00:00'::interval
max_retry | integer | not null default 0
skip_analyze | boolean | not null default false
Indexes:
"tables_pkey" PRIMARY KEY, btree (id)
"tables_tabschema_tabname_key" UNIQUE CONSTRAINT, btree (tabschema, tabname)
Check constraints:
"tables_free_space_extra_check" CHECK (free_space_extra >= 0 AND free_space_extra < 100)
"tables_min_size_check" CHECK (min_size > 0.0::double precision)
"tables_task_interval_check" CHECK (task_interval >= '00:01:00'::interval)
Referenced by:
TABLE "squeeze.tables_internal" CONSTRAINT "tables_internal_table_id_fkey" FOREIGN KEY (table_id) R
EFERENCES squeeze.tables(id) ON DELETE CASCADE
TABLE "squeeze.tasks" CONSTRAINT "tasks_table_id_fkey" FOREIGN KEY (table_id) REFERENCES squeeze.ta
bles(id) ON DELETE CASCADE
Triggers:
tables_internal_trig AFTER INSERT ON squeeze.tables FOR EACH ROW EXECUTE PROCEDURE squeeze.tables_i
nternal_trig_func()
如果要使用pg_squeeze重建表需要插入一条记录进入到squeeze.tables这个表中,最简单的例子就是:insert into squeeze.tables(tabschema,tabname,first_check) values('public','a',now());
下面说下这个表中的字段的含义。
tabschema:就是表的模式名。
tabname:表示表名。
clustering_index:表示重建表时,表数据的物理顺序按照该索引进行聚簇。
rel_tablespace:表示表重建时,移动到哪个表空间中。
ind_tablespace:这个一个二维数组,表示索引和表空间的映射关系。
task_interval:表示两个任务相隔的最小时间,默认是1小时。
first_check:表示第一次统计时间。
free_space_extra:表示空闲空间超过多少时就会对表进行重建,默认是50。
vacuum_max_age:当进行一次vacuum后,认为fsm是有效的最大时间,默认1小时。
max_retry:当重建表失败时最大的重新尝试的次数,默认是0.
skip_analyse:跳过对表进行analyse,默认是false。
启动pg_squeeze的进程需要调用:SELECT squeeze.start_worker();
关闭pg_squeeze的进程需要调用:SELECT squeeze.stop_worker();
默认pg_squeeze进程进行检查是否重建表的时间由squeeze.worker_naptime这个参数来决定,默认时间是1分钟。
可以设置squeeze.max_xlock_time控制最大占用锁的时间。
简单例子
postgres=# insert into squeeze.tables
postgres-# (tabschema,tabname,first_check,free_space_extra)
postgres-# values('public','a',now(),20);
INSERT 0 1
postgres=# select squeeze.start_worker();
start_worker
1009
(1 row)
postgres=# select * from squeeze.tables_internal;
table_id | class_id | class_id_toast | free_space | last_task_created | last_task_finished |
---|---|---|---|---|---|
5 | 71866 | 0 | 0.346762447033898 |
(1 row)
我们往squeeze.tables插入了一条记录,如果空闲空间大于20%就会重建表,查询squeeze.tables_internal,空闲空间是0.34,下面模拟空闲空间超过20%的情况。
postgres=# dt+ a
List of relations
Schema | Name | Type | Owner | Size | Description |
---|---|---|---|---|---|
public | a | table | postgres | 69 MB |
(1 row)
postgres=# delete from a where id<500000;
DELETE 499999
postgres=# select * from squeeze.tables_internal;
table_id | class_id | class_id_toast | free_space | last_task_created | last_task_finished |
---|---|---|---|---|---|
5 | 71866 | 0 | 0.346762447033898 |
(1 row)
postgres=# select * from squeeze.tables_internal;
table_id | class_id | class_id_toast | free_space | last_task_created | last_task_finished |
---|---|---|---|---|---|
5 | 71866 | 0 | 0.346762447033898 |
(1 row)
postgres=# select * from squeeze.tables_internal;
table_id | class_id | class_id_toast | free_space | last_task_created | last_task_finished |
---|---|---|---|---|---|
5 | 71866 | 0 | 22.2685491701977 |
(1 row)
postgres=# dt+ a
List of relations
Schema | Name | Type | Owner | Size | Description |
---|---|---|---|---|---|
public | a | table | postgres | 52 MB |
(1 row)
postgres=# select * from squeeze.tables_internal;
table_id | class_id | class_id_toast | free_space | last_task_created | last_task_finished
5 | 71866 | 0 | 0.354176768699156 | | 2017-01-01 23:14:40.034
685+08
(1 row)
开始前表大小是69M,delete了50W条数据,如果是正常情况,delete后的空间是不会释放的,用了插件后,更新完统计信息后获得free_space=22.26大于我们设定的20,所以对表进行重建,之后发现表的大小变成了52M,新的统计信息有了最后一次的完成时间。