PostgreSQL 10.0 内置分区表

标签

PostgreSQL , 10.0 , 分区表 , partitiion table , range , list


背景

PostgreSQL 和它的LOGO大象一样,给人非常强大的安全感。

就拿它的Feature来说,一个大的feature要打磨很多年才能正式的合并到master分支。

比如并行计算的特性,从9.4就开始准备,加入了work process和dynamic shared memory的功能,奠定了多进程并行执行的基础。

一致到9.6,经历了3年的开发,大量的测试,终于RELEASE了。

今天要说一说它的分区表,经历了几年的酝酿,终于在10.0加入到master了。(PG的企业版本EDB很早就支持分区表了)

如果你现在需要这个功能,可以使用postgrespro的插件, pg_pathman,否则就等10.0吧,明年9月份左右release。

《PostgreSQL 9.5+ 高效分区表实现 - pg_pathman》

PostgreSQL 10.0 分区表的设计

PostgreSQL的分区表依旧使用了继承的特性,好消息是, 终于不需要手工写规则了。

在使用方面,我们需要先创建主表,然后创建分区(即子表)。老顽固啊,就是要让你记住PG是有继承的概念的吗?

目前支持range、list分区(10.0 release时应该会支持更多的方法),分区列的类型必须支持btree索引接口(几乎涵盖所有类型, 后面会说到检查方法)。

语法

1. 创建主表

[ PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [, ... ] ) ]

2. 创建分区

PARTITION OF parent_table [ (
  { column_name [ column_constraint [ ... ] ]
    | table_constraint }
    [, ... ]
) ] FOR VALUES partition_bound_spec  

and partition_bound_spec is:  

{ IN ( expression [, ...] )   -- list分区
  |
  FROM ( { expression | UNBOUNDED } [, ...] ) TO ( { expression | UNBOUNDED } [, ...] ) }  -- range分区, unbounded表示无限小或无限大

语法解释

1. 创建主表

partition by 指定分区表的类型range或list

指定分区列,或表达式作为分区键。

range分区表键:支持指定多列、或多表达式,支持混合(键,非表达式中的列,会自动添加not null的约束)

list分区表键:支持单个列、或单个表达式

分区键必须有对应的btree索引方法的ops(可以查看系统表得到)

select typname from pg_type where oid in (select opcintype from pg_opclass);

主表不会有任何数据,数据会根据分区规则进入对应的分区表

如果插入数据时,分区键的值没有匹配的分区,会报错

不支持全局的unique, primary key, exclude, foreign key约束,只能在对应的分区建立这些约束

PARTITION BY { RANGE | LIST } ( { column_name | ( expression ) } [ opclass ] [, ...] )  

The optional PARTITION BY clause specifies a strategy of partitioning the table.   

The table thus created is called a partitioned table. The parenthesized list of columns or expressions forms the partition key for the table.   

When using range partitioning, the partition key can include multiple columns or expressions, but for list partitioning, the partition key must consist of a single column or expression.   

If no btree operator class is specified when creating a partitioned table, the default btree operator class for the datatype will be used. If there is none, an error will be reported.   

A partitioned table is divided into sub-tables (called partitions), which are created using separate CREATE TABLE commands.   

The partitioned table is itself empty. A data row inserted into the table is routed to a partition based on the value of columns or expressions in the partition key.   

If no existing partition matches the values in the new row, an error will be reported.  

Partitioned tables do not support UNIQUE, PRIMARY KEY, EXCLUDE, or FOREIGN KEY constraints;   

however, you can define these constraints on individual partitions.  

When using range partitioning, a NOT NULL constraint is added to each non-expression column in the partition key.

2. 创建分区

主表创建好之后,需要再创建分区(为了体现继承么?就不能一次干掉?)

创建分区表需要指定它的主表是哪个?

指定分区键的属性(范围,LIST值),范围,LIST不能有重叠(这个很好理解,否则重叠部分的数据到底插到哪个分区去呢?)

分区表和主表的 列数量,定义 必须完全一致,(包括OID也必须一致,要么都有,要么都没有)

可以为分区表的列单独增加Default值,或约束。

用户还可以对分区表增加表级约束

如果新增的分区表check约束,名字与主表的约束名一致,则约束内容必须与主表一致

当用户往主表插入数据库时,记录被自动路由到对应的分区,如果没有合适的分区,则报错

如果更新数据,并且更新后的KEY导致数据需要移动到另一分区,则会报错,(意思是分区键可以更新,但是不支持更新后的数据移出到别的分区表)

修改主表的字段名,字段类型时,会自动同时修改所有的分区

TRUNCATE 主表时,会清除所有继承表分区的记录(如果有多级分区,则会一直清除到所有的直接和间接继承的分区)

如果要清除单个分区,请对分区进行操作

如果要删除分区表,可以使用DROP TABLE的DDL语句,注意这个操作会对主表也加access exclusive lock。

PARTITION OF parent_table FOR VALUES partition_bound_spec  

partition_bound_spec is:    

{ IN ( expression [, ...] ) |
  FROM ( { expression | UNBOUNDED } [, ...] ) TO ( { expression | UNBOUNDED } [, ...] ) }  

Creates the table as partition of the specified parent table.  

The partition bound specification must correspond to the partitioning method and partition key of the parent table, and must not overlap with any existing partition of that parent.  

A partition cannot have columns other than those inherited from the parent. That includes the oid column, which can be specified using the WITH (OIDS) clause.   

Defaults and constraints can optionally be specified for each of the inherited columns.   

One can also specify table constraints in addition to those inherited from the parent.   

If a check constraint with the name matching one of the parent's constraint is specified, it is merged with the latter, provided the specified condition is same.  

Rows inserted into a partitioned table will be automatically routed to the correct partition. If no suitable partition exists, an error will occur.   

Also, if updating a row in a given partition causes it to move to another partition due to the new partition key, an error will occur.  

A partition must have the same column names and types as the table of which it is a partition.   

Therefore, modifications to the column names or types of the partitioned table will automatically propagate to all children, as will operations such as TRUNCATE which normally affect a table and all of its inheritance children.   

It is also possible to TRUNCATE a partition individually, just as for an inheritance child.   

Note that dropping a partition with DROP TABLE requires taking an ACCESS EXCLUSIVE lock on the parent table.

例子

测试版本编译

wget https://git.postgresql.org/gitweb/?p=postgresql.git;a=snapshot;h=55caaaeba877eac1feb6481fb413fa04ae9046ac;sf=tgz  

tar -zxvf postgresql-55caaae.tar.gz  

cd postgresql-55caaae  

./configure --prefix=/home/digoal/pgsql10.0  

make world -j 32  

make install-world  

export PGPORT=5299
export PGDATA=/disk1/pgdata/pg_root10
export LANG=en_US.utf8
export PGHOME=/home/digoal/pgsql10.0
export LD_LIBRARY_PATH=$PGHOME/lib:/lib64:/usr/lib64:/usr/local/lib64:/lib:/usr/lib:/usr/local/lib:$LD_LIBRARY_PATH
export DATE=`date +"%Y%m%d%H%M"`
export PATH=$PGHOME/bin:$PATH:.
export MANPATH=$PGHOME/share/man:$MANPATH
export PGHOST=$PGDATA
export PGUSER=postgres
export PGDATABASE=postgres  

initdb -D $PGDATA -U postgres -E SQL_ASCII --locale=C  

vi $PGDATA/postgresql.conf
cat postgresql.conf|grep "^[a-z]"|awk -F "#" '{print $1}'  

listen_addresses = '0.0.0.0'
port = 5299
max_connections = 500
superuser_reserved_connections = 13
unix_socket_directories = '.'
shared_buffers = 16GB
maintenance_work_mem = 1024MB
dynamic_shared_memory_type = posix
bgwriter_delay = 10ms
bgwriter_lru_maxpages = 1000
bgwriter_lru_multiplier = 5.0
bgwriter_flush_after = 0
max_parallel_workers_per_gather = 0
max_parallel_workers = 0
old_snapshot_threshold = -1
backend_flush_after = 0
wal_buffers = 512MB
wal_writer_delay = 10ms
wal_writer_flush_after = 0
checkpoint_timeout = 55min
max_wal_size = 128GB
min_wal_size = 8GB
checkpoint_completion_target = 0.5
checkpoint_flush_after = 0
random_page_cost = 1.0
effective_cache_size = 400GB
log_destination = 'csvlog'
logging_collector = on
log_truncate_on_rotation = on
log_checkpoints = on
log_connections = on
log_disconnections = on
log_error_verbosity = verbose
log_timezone = 'PRC'
log_autovacuum_min_duration = 0
datestyle = 'iso, mdy'
timezone = 'PRC'
lc_messages = 'C'
lc_monetary = 'C'
lc_numeric = 'C'
lc_time = 'C'
default_text_search_config = 'pg_catalog.english'  

pg_ctl start

查找可用的opclass

由于分区表的键值列必须支持btree索引,所以建议确认一下。

创建主表时,需要指定ops,如果没有指定,会自动选择类型默认的btree ops.

postgres=# select opcintype::regtype,opcname from pg_opclass ;
          opcintype          |        opcname
-----------------------------+------------------------
 abstime                     | abstime_ops
 anyarray                    | array_ops
 anyarray                    | array_ops
 bit                         | bit_ops
 boolean                     | bool_ops
 character                   | bpchar_ops
 character                   | bpchar_ops
 。。。。。。

分区表

1. range 分区表

例子为按时间字段分区的分区表,用户在创建主表时,指定分区键,创建分区时,指定每个分区的范围。

1.1 主表

range分区表,支持混合式的分区键(多列,多表达式,或者混合式)

和前面说的一样,不能使用全局PK

postgres=# create table t_range(id int primary key, info text, crt_time timestamp) partition by range (crt_time, mod(hashtext(info), 4));
ERROR:  0A000: primary key constraints are not supported on partitioned tables
LINE 1: create table t_range(id int primary key, info text, crt_time...
                                    ^
LOCATION:  transformColumnDefinition, parse_utilcmd.c:620  

postgres=# create table t_range(id int, info text, crt_time timestamp) partition by range (crt_time);
CREATE TABLE

1.2 分区

postgres=# create table t_range_0_201610 partition of t_range (id  primary key, info , crt_time ) for values from ('2016-10-01') to ('2016-11-01');  -- >= 20161001 and < 20161101
CREATE TABLE
postgres=# create table t_range_0_201611 partition of t_range (id  primary key, info , crt_time ) for values from ('2016-11-01') to ('2016-12-01');  -- >= 20161101 and < 20161201
CREATE TABLE

甚至你可以将分区表放到不同的schema下面

postgres=# create schema x;
CREATE SCHEMA

postgres=# create table x.t_range_0_201612 partition of t_range (id  primary key, info , crt_time ) for values from ('2016-12-01') to ('2017-01-01');
CREATE TABLE

postgres=# \d+ t_range
                                             Table "public.t_range"
  Column  |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
 id       | integer                     |           |          |         | plain    |              |
 info     | text                        |           |          |         | extended |              |
 crt_time | timestamp without time zone |           | not null |         | plain    |              |
Partition key: RANGE (crt_time)
Partitions: t_range_0_201610 FOR VALUES FROM ('2016-10-01 00:00:00') TO ('2016-11-01 00:00:00'),
            t_range_0_201611 FOR VALUES FROM ('2016-11-01 00:00:00') TO ('2016-12-01 00:00:00'),
            x.t_range_0_201612 FOR VALUES FROM ('2016-12-01 00:00:00') TO ('2017-01-01 00:00:00')

2. list 分区表

2.1 主表

postgres=# create table t_list(id int, info text, crt_time timestamp) partition by list ( mod(hashtext(info), 4) );
CREATE TABLE

2.2 分区

postgres=# create table t_list_0 partition of t_list (id  primary key, info , crt_time ) for values in (0);
CREATE TABLE
postgres=# create table t_list_1 partition of t_list (id  primary key, info , crt_time ) for values in (1);
CREATE TABLE
postgres=# create table t_list_2 partition of t_list (id  primary key, info , crt_time ) for values in (2);
CREATE TABLE
postgres=# create table t_list_3 partition of t_list (id  primary key, info , crt_time ) for values in (3);
CREATE TABLE

多级分区

创建主表

create table t_range_list(id int, info text, crt_time timestamp) partition by list ( mod(hashtext(info), 4) );

创建一级分区,主表

create table t_range_list_0 partition of t_range_list (id  , info , crt_time ) for values in (0) partition by range (crt_time);
create table t_range_list_1 partition of t_range_list (id  , info , crt_time ) for values in (1) partition by range (crt_time);
create table t_range_list_2 partition of t_range_list (id  , info , crt_time ) for values in (2) partition by range (crt_time);
create table t_range_list_3 partition of t_range_list (id  , info , crt_time ) for values in (3) partition by range (crt_time);

创建2级分区表

create table t_range_list_0_201611 partition of t_range_list_0 (id  primary key, info , crt_time ) for values from ('2016-10-01') to ('2016-11-01');
create table t_range_list_0_201612 partition of t_range_list_0 (id  primary key, info , crt_time ) for values from ('2016-11-01') to ('2016-12-01');  

create table t_range_list_1_201611 partition of t_range_list_1 (id  primary key, info , crt_time ) for values from ('2016-10-01') to ('2016-11-01');
create table t_range_list_1_201612 partition of t_range_list_1 (id  primary key, info , crt_time ) for values from ('2016-11-01') to ('2016-12-01');  

create table t_range_list_2_201611 partition of t_range_list_2 (id  primary key, info , crt_time ) for values from ('2016-10-01') to ('2016-11-01');
create table t_range_list_2_201612 partition of t_range_list_2 (id  primary key, info , crt_time ) for values from ('2016-11-01') to ('2016-12-01');  

create table t_range_list_3_201611 partition of t_range_list_3 (id  primary key, info , crt_time ) for values from ('2016-10-01') to ('2016-11-01');
create table t_range_list_3_201612 partition of t_range_list_3 (id  primary key, info , crt_time ) for values from ('2016-11-01') to ('2016-12-01');

执行计划

1. 分区键条件建议使用同类型的常量、如果是函数则必须使用返回值与分区键类型一致,stable或immutable的函数。

postgres=# explain select * from t_range where crt_time=now()::timestamp;  -- 如果需要转换,转换函数必须为immutable(常量),这样可以在进行逻辑推理前被调用
                                QUERY PLAN
---------------------------------------------------------------------------
 Append  (cost=0.00..23929.55 rows=14 width=42)
   ->  Seq Scan on t_range  (cost=0.00..0.00 rows=1 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201610  (cost=0.00..23870.00 rows=1 width=17)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201611  (cost=0.00..29.78 rows=6 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201612  (cost=0.00..29.78 rows=6 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
(9 rows)
postgres=# create or replace function sysdate() returns timestamp as $$
  select now()::timestamp ;
$$ language sql strict immutable;
CREATE FUNCTION

postgres=# explain select * from t_range where crt_time=sysdate();
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Append  (cost=0.00..24.12 rows=7 width=44)
   ->  Seq Scan on t_range  (cost=0.00..0.00 rows=1 width=44)
         Filter: (crt_time = '2016-12-16 09:58:03.246322'::timestamp without time zone)
   ->  Seq Scan on t_range_0_201612  (cost=0.00..24.12 rows=6 width=44)
         Filter: (crt_time = '2016-12-16 09:58:03.246322'::timestamp without time zone)
(5 rows)

返回类型一致的C代码stable函数也可以被排除,否则会被解释

postgres=# create or replace function sysdate() returns timestamp as $$
  select now()::timestamp ;
$$ language sql strict stable;
CREATE FUNCTION

postgres=# explain select * from t_range where crt_time=sysdate();
                                QUERY PLAN
---------------------------------------------------------------------------
 Append  (cost=0.00..23929.55 rows=14 width=42)
   ->  Seq Scan on t_range  (cost=0.00..0.00 rows=1 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201610  (cost=0.00..23870.00 rows=1 width=17)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201611  (cost=0.00..29.78 rows=6 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
   ->  Seq Scan on t_range_0_201612  (cost=0.00..29.78 rows=6 width=44)
         Filter: (crt_time = (now())::timestamp without time zone)
(9 rows)

返回类型一致的C代码stable函数也可以被排除

postgres=# create table p(id int, info text, crt_time timestamptz);
CREATE TABLE
postgres=# create table t(like p) inherits(p);
NOTICE:  merging column "id" with inherited definition
NOTICE:  merging column "info" with inherited definition
NOTICE:  merging column "crt_time" with inherited definition
CREATE TABLE
postgres=# create table p1(like p) inherits(p);
NOTICE:  merging column "id" with inherited definition
NOTICE:  merging column "info" with inherited definition
NOTICE:  merging column "crt_time" with inherited definition
CREATE TABLE
postgres=# create table p2(like p) inherits(p);
NOTICE:  merging column "id" with inherited definition
NOTICE:  merging column "info" with inherited definition
NOTICE:  merging column "crt_time" with inherited definition
CREATE TABLE
postgres=# alter table t add constraint ck check(crt_time >='2016-11-01' and crt_time <'2016-12-01');
ALTER TABLE
postgres=# alter table p1 add constraint ck check(crt_time >='2016-10-01' and crt_time <'2016-11-01');
ALTER TABLE
postgres=# alter table p2 add constraint ck check(crt_time >='2016-09-01' and crt_time <'2016-10-01');
ALTER TABLE
postgres=# explain select * from p where crt_time=now();
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Append  (cost=0.00..0.00 rows=1 width=44)
   ->  Seq Scan on p  (cost=0.00..0.00 rows=1 width=44)
         Filter: (crt_time = '2016-12-16 10:02:40.483355+08'::timestamp with time zone)
(3 rows)

绑定分区,解绑分区

ALTER TABLE可以将表绑定到分区表的某个分区,也可以将某个已有分区从分区表剔除。

ALTER TABLE [ IF EXISTS ] name
    ATTACH PARTITION partition_name FOR VALUES partition_bound_spec
ALTER TABLE [ IF EXISTS ] name
    DETACH PARTITION partition_name

解释

绑定时,需要指定分区键的边界(范围、或LIST值)

列名与主表一致、列类型一致、列顺序一致、NOT NULL、CHECK约束一致、不建议UNIQUE,PK,FK。

不能有任何主表非继承的CHECK约束,(建议对约束重建,不要加not inherit属性)

加入的分区需要进行全表扫描,确认所有的记录都在指定的分区键边界内。

如果要避免全表扫描,建议在执行绑定前,对这个表加入CHECK约束,确保约束可以保证记录都在边界内。 但是这种方法不适用于分区键包含表达式并且分区不允许NULL值的情况。

ATTACH PARTITION partition_name FOR VALUES partition_bound_spec
This form attaches an existing table (which might itself be partitioned) as a partition of the target table using the same syntax for partition_bound_spec as CREATE TABLE. 

The partition bound specification must correspond to the partitioning strategy and partition key of the target table. 

The table to be attached must have all the same columns as the target table and no more; moreover, the column types must also match. 

Also, it must have all the NOT NULL and CHECK constraints of the target table. Currently UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints are not considered. 

If any of the CHECK constraints of the table being attached is marked NO INHERIT, the command will fail; such a constraint must be recreated without the NO INHERIT clause.

A full table scan is performed on the table being attached to check that no existing row in the table violates the partition constraint. 

It is possible to avoid this scan by adding a valid CHECK constraint to the table that would allow only the rows satisfying the desired partition constraint before running this command. 

It will be determined using such a constraint that the table need not be scanned to validate the partition constraint. 

This does not work, however, if any of the partition keys is an expression and the partition does not accept NULL values. 

If attaching a list partition that will not accept NULL values, also add NOT NULL constraint to the partition key column, unless it's an expression.
DETACH PARTITION partition_name
This form detaches specified partition of the target table. The detached partition continues to exist as a standalone table, but no longer has any ties to the table from which it was detached.

All the actions except RENAME, SET TABLESPACE, SET SCHEMA, ATTACH PARTITION, and DETACH PARTITION can be combined into a list of multiple alterations to apply in parallel. 

For example, it is possible to add several columns and/or alter the type of several columns in a single command. This is particularly useful with large tables, since only one pass over the table need be made.

You must own the table to use ALTER TABLE. To change the schema or tablespace of a table, you must also have CREATE privilege on the new schema or tablespace. 

To add the table as a new child of a parent table, you must own the parent table as well. Also, to attach a table as a new partition of the table, you must own the table being attached. 

To alter the owner, you must also be a direct or indirect member of the new owning role, and that role must have CREATE privilege on the table's schema. 

(These restrictions enforce that altering the owner doesn't do anything you couldn't do by dropping and recreating the table. 

However, a superuser can alter ownership of any table anyway.) To add a column or alter a column type or use the OF clause, you must also have USAGE privilege on the data type.

性能测试

range 分区表

插入

postgres=# insert into t_range select generate_series(1,1000000),'test','2016-10-01';
INSERT 0 1000000
Time: 3849.514 ms (00:03.850)  

直接插分区表
postgres=# truncate t_range;
TRUNCATE TABLE
Time: 72.181 ms
postgres=# insert into t_range_0_201610 select generate_series(1,1000000),'test','2016-10-01';
INSERT 0 1000000
Time: 3587.772 ms (00:03.588)

查询,主表未消除

postgres=# explain (analyze,verbose,timing,costs,buffers) select * from t_range where id=1 and crt_time='2016-10-01';
                                                                      QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.00..2.45 rows=2 width=30) (actual time=0.037..0.038 rows=1 loops=1)
   Buffers: shared hit=4
   ->  Seq Scan on public.t_range  (cost=0.00..0.00 rows=1 width=44) (actual time=0.020..0.020 rows=0 loops=1)
         Output: t_range.id, t_range.info, t_range.crt_time
         Filter: ((t_range.id = 1) AND (t_range.crt_time = '2016-10-01 00:00:00'::timestamp without time zone))
   ->  Index Scan using t_range_0_201610_pkey on public.t_range_0_201610  (cost=0.42..2.45 rows=1 width=17) (actual time=0.016..0.016 rows=1 loops=1)
         Output: t_range_0_201610.id, t_range_0_201610.info, t_range_0_201610.crt_time
         Index Cond: (t_range_0_201610.id = 1)
         Filter: (t_range_0_201610.crt_time = '2016-10-01 00:00:00'::timestamp without time zone)
         Buffers: shared hit=4
 Planning time: 0.248 ms
 Execution time: 0.069 ms
(12 rows)

on conflict do

postgres=# insert into t_range select generate_series(1,1000000),'test','2016-10-01' on conflict do nothing;
ERROR:  0A000: ON CONFLICT clause is not supported with partitioned tables
LOCATION:  transformInsertStmt, analyze.c:825
Time: 0.350 ms

参考

1. https://www.postgresql.org/docs/devel/static/sql-createtable.html

《PostgreSQL 9.5+ 高效分区表实现 - pg_pathman》

《PostgreSQL 优化器逻辑推理能力 源码解析》

时间: 2024-08-01 14:21:46

PostgreSQL 10.0 内置分区表的相关文章

PostgreSQL 10.0 preview 功能增强 - 分区表(hash,range,list)

标签 PostgreSQL , 10.0 , 分区表 背景 PostgreSQL 10.0将支持range,list分区表,同时hash分区处于POC阶段(同时还有一些需要改进的地方,例如优化器部分). 如果你使用的是10.0以前的版本,可以使用pg_pathman插件实现分区,pg_pathman已经非常的完美. PostgreSQL支持伪表作为分区,例如外部表,物化视图.伪表作为分区有很多可以适合的使用场景,例如将外部表作为分区,则可以实现sharding场景. 分区表用法 https://

PostgreSQL 10.0 preview 功能增强 - 分区表(list default)

标签 PostgreSQL , 10.0 , 分区表 , 默认分区 背景 PostgreSQL 10.0将支持range,list分区表,同时hash分区处于POC阶段(同时还有一些需要改进的地方,例如优化器部分). 如果你使用的是10.0以前的版本,可以使用pg_pathman插件实现分区,pg_pathman已经非常的完美. PostgreSQL支持伪表作为分区,例如外部表,物化视图.伪表作为分区有很多可以适合的使用场景,例如将外部表作为分区,则可以实现sharding场景. 分区表用法 h

元旦技术大礼包 - 2017金秋将要发布的PostgreSQL 10.0已装备了哪些核武器?

标签 PostgreSQL , 10.0 , 金秋 , 元旦 , 大礼包 , commitfest 背景 早上送给大家的新年大礼包,一年一个大版本是PostgreSQL社区的传统,虽然发布时间通常为秋天,还有一段时间,但是已经迫不及待地想看看2017金秋将要发布的10.0版本已经装备了哪些核武器. 放心,还会有一波又一波的feature和增强搭上开往2017金秋的列车,本文提到的可能只是其中的某一节车厢沃,PGer是不是开始有一点振奋人心的感觉啦. 1. 并行计算专属动态共享内存区,(加速索引扫

PostgreSQL 10.0 preview 功能增强 - 角色化权限管理

标签 PostgreSQL , 10.0 , 内置角色 , 监控角色 , 管理用户会话角色 , pg_backend_pid , pg_monitor 背景 PostgreSQL 10.0 开始植入了一些内置的角色,例如pg_backend_pid角色可用于cancel, terminate任何PID,除此之外没有其他超级用户的权限,这种用户可以给DBA或者给一些业务OWNER使用,便于它们在紧急情况下行使权力,杀掉一些会话. 同时为了便于DBA或者业务OWNER查看到数据库的健康状况,Post

PostgreSQL 10.0 preview sharding增强 - 支持分布式事务

标签 PostgreSQL , 10.0 , sharding , 分布式事务 , 2pc , 两阶段事务 背景 作为一个完整的分布式数据库(sharding),没有分布式事务支持是不行的. 什么是分布式事务呢?比如我们把一个数据库比作一个小朋友,每个小朋友都有100块钱,然后A小朋友给了B小朋友20块钱,这样的话应该是A剩余80块,B剩余120块.如果在交易过程中B小朋友不小心把20块弄丢了,那么会怎么样呢? 理论上应该是交易不成功,A和B都回到100块的状态. 不应该出现中间状态. Post

PostgreSQL 10.0 preview 性能增强 - 分区表性能增强(plan阶段加速)

标签 PostgreSQL , 10.0 , 分区表 , 子表 , 元信息搜索性能增强 背景 PostgreSQL 10.0 增强了分区表的子表搜索性能,对于涉及分区表包含子表特别多的QUERY,可以提升性能. 性能分析 get_tabstat_entry, find_all_inheritors成为主要瓶颈. Hello. I decided to figure out whether current implementation of declarative partitioning has

PostgreSQL 10.0 preview 功能增强 - 触发器函数内置中间表

标签 PostgreSQL , 10.0 , 触发器 , 中间表 , OLD , NEW 背景 在触发器中,如果要提取触发该事件的记录,使用OLD和NEW关键字. OLD.* , NEW.* 提取 对于for statement after触发器,触发的记录数可能是很多的,PostgreSQL 10.0增加了一个功能,中间表. 在触发器函数中,可以使用这个中间表,中间表的数据就是触发器涉及的数据,中级镖的功能支持after触发器(因为after后才有全部的记录呀). 语法 [ REFERENCI

PostgreSQL 10.0 解读

背景 本文参考当前的release notes以及git, committe fest编写,10.0还没有正式release,部分内容在正式release时可能会修改,同时会新增新的内容. 迁移到10.0的注意事项 迁移时,请注意不兼容的地方. 1. 使用pg_upgrade升级时,hash index 需要重建.(因为10.0为了支持hash index WAL,存储结构改变了.) 2. $PGDATA/pg_log, pg_xlog, pg_clog目录分别重命名为log, pg_wal,

PostgreSQL 10.0 preview 性能增强 - 推出JIT开发框架(朝着HTAP迈进)

标签 PostgreSQL , 10.0 , HTAP , 动态编译 , JIT , LLVM , 表达式 , 函数跳转 背景 数据库发展了几十年,出现了很多产品,有面向OLTP(在线事务处理)的,有面向OLAP(在线分析)的. 虽然两个场景各有需求特色,但是企业需要为其需求买单,因为目前很少有产品可以同时满足在线处理和在线分析的需求. 比如一家企业,通常都有业务的波峰波谷,比如游戏业务,通常波谷可能是在凌晨,因为大多数人都睡了.而波峰可能出现在每天的工作闲时.游戏运营时段.节假日等. 为了分析