• 【PostgreSQL-9.6.3】分区表


    PostgreSQL中的分区表是通过表继承来实现的(表继承博客http://www.cnblogs.com/NextAction/p/7366607.html)。创建分区表的步骤如下:

    (1)创建“父表”,所有的分区表都从这张表继承。“父表”中不存数据,也不要定义约束和索引。

    (2)创建“子表”,所有“子表”都是从“父表”中继承而来。这些“子表”就是所谓的分区,其实它们也是PostgreSQL表。

    (3)给分区表创建约束。

    (4)在分区表上创建索引。

    (5)创建触发器,把对“父表”的插入重定向到分区表中。

    (6)确保postgresql.conf中constraint_exclusion的配置参数是打开状态。打开后,可以确保查询智能的只查询分区表,而不会对其他分区表进行查询。

    下面是创建分区表的例子:

    --创建销售明细表,作为“父表”
    create table sales_detail (
    product_id    int    not null,
    price         numeric(12,2),
    amount        int    not null,
    sale_date     date   not null,
    buyer         varchar(40),
    buyer_contact text
    );
    
    --根据销售日期sale_date字段,每个季度作为一个分区,创建分区表
    create table sales_detail_Y2017Q01(check (sale_date >= date '2017-01-01' and sale_date < date '2017-04-01') ) inherits (sales_detail);
    
    create table sales_detail_Y2017Q02(check (sale_date >= date '2017-04-01' and sale_date < date '2017-07-01') ) inherits (sales_detail);
    
    create table sales_detail_Y2017Q03(check (sale_date >= date '2017-07-01' and sale_date < date '2017-10-01') ) inherits (sales_detail);
    
    create table sales_detail_Y2017Q04(check (sale_date >= date '2017-10-01' and sale_date < date '2018-01-01') ) inherits (sales_detail);
    
    --在分区键sale_detail上创建索引
    create index sales_detail_Y2017Q01_sale_date on sales_detail_Y2017Q01 (sale_date);
    
    create index sales_detail_Y2017Q02_sale_date on sales_detail_Y2017Q02 (sale_date);
    
    create index sales_detail_Y2017Q03_sale_date on sales_detail_Y2017Q03 (sale_date);
    
    create index sales_detail_Y2017Q04_sale_date on sales_detail_Y2017Q04 (sale_date);
    
    --创建触发器,当向sales_detail表中插入数据时,可以重定向插入到分区表中
    create or replace function sales_detail_insert_trigger()
    returns trigger as $$
    begin
        if (new.sale_date >= date '2017-01-01' and new.sale_date < date '2017-04-01') then
        insert into sales_detail_Y2017Q01 values (new.*);
        elsif (new.sale_date >= date '2017-04-01' and new.sale_date < date '2017-07-01') then
        insert into sales_detail_Y2017Q02 values (new.*);
        elsif (new.sale_date >= date '2017-07-01' and new.sale_date < date '2017-10-01') then
        insert into sales_detail_Y2017Q03 values (new.*);
        elsif (new.sale_date >= date '2017-10-01' and new.sale_date < date '2018-01-01') then
        insert into sales_detail_Y2017Q04 values (new.*);
        else 
        raise exception 'Date out of range.Fix the sales_detail_insert_trigger () function!';
      end if;
      return null;
    end;
    $$
    language plpgsql;
    
    create trigger insert_sales_detail_trigger 
    before insert on sales_detail
    for each row execute procedure sales_detail_insert_trigger ();
    
    --设置constraint_exclusion参数为“partition”状态。此参数默认为“partition”
    set constrait_exclusion 'partition'

    测试分区表:

    --向“父表”中插入一条数据
    test=# insert into sales_detail values (1,23.22,1,date'2017-08-16','zhaosi','xiangyashan222hao');
    
    --数据已经插入到分区表中
    test=# select * from sales_detail_Y2017Q03;
     product_id | price | amount | sale_date  | buyer  |   buyer_contact   
    ------------+-------+--------+------------+--------+-------------------
              1 | 23.22 |      1 | 2017-08-16 | zhaosi | xiangyashan222hao
    (1 row)
    
    --并且查询“父表”也可以查到插入的数据
    test=# select * from sales_detail;
     product_id | price | amount | sale_date  | buyer  |   buyer_contact   
    ------------+-------+--------+------------+--------+-------------------
              1 | 23.22 |      1 | 2017-08-16 | zhaosi | xiangyashan222hao
    (1 row)
    
    --通过查看执行计划,可以看出当查询数据时,数据库会自动的去sales_detail_Y2017Q03分区表中查找,而不会扫描所有的分区表。
    test=# explain select * from sales_detail where sale_date=date'2017-08-16';
                                                 QUERY PLAN                                             
    ----------------------------------------------------------------------------------------------------
     Append  (cost=0.00..9.50 rows=3 width=158)
       ->  Seq Scan on sales_detail  (cost=0.00..0.00 rows=1 width=158)
             Filter: (sale_date = '2017-08-16'::date)
       ->  Bitmap Heap Scan on sales_detail_y2017q03  (cost=4.16..9.50 rows=2 width=158)
             Recheck Cond: (sale_date = '2017-08-16'::date)
             ->  Bitmap Index Scan on sales_detail_y2017q03_sale_date  (cost=0.00..4.16 rows=2 width=0)
                   Index Cond: (sale_date = '2017-08-16'::date)
    (7 rows)

    总结:

    删除分区表中的子表,不会使触发器失效,只是当向被删除表中插入数据时会报错。

    创建分区表过程中的触发器,可以用“规则”来代替,但触发器比“规则”更有优势,再此不再赘述。

    The End!

    2017-08-17

  • 相关阅读:
    【历史时刻】从学生到社会独立人——硕士毕业
    Linux 常用命令
    LInux系统下搭建redis集群
    docker 下创建自定义网络,并在运行容器时绑定网络和ip
    docker下安装mysql镜像
    windows下将consul注册为系统服务
    Sql批量替换字段字符,Sql批量替换多字段字符,Sql替换字符
    gerrit安装配置
    Linux安装jdk8及环境变量配置
    iTerm2配置优化
  • 原文地址:https://www.cnblogs.com/NextAction/p/7376774.html
Copyright © 2020-2023  润新知