PostgreSQL分表
PostgreSQL分表
测试表
创建表以存储全部数据
1 | CREATE TABLE IF NOT EXISTS a_user_all ( |
随机字符串生成function
1 | Create or replace function random_string(length integer) |
插入数据脚本
1 | INSERT INTO |
创建主表
TIMESTAMP(6):小数点右边最多存储6位数字(PostgreSQL 12.6)
使用序列主键(推荐)
1 | CREATE SEQUENCE a_user_seq MINVALUE 1 NO MAXVALUE START WITH 1 INCREMENT BY 1 CACHE 1; |
ID自动增长
1 | CREATE TABLE IF NOT EXISTS a_user ( |
删除
1 | DROP INDEX idx_uk_a_user_account; |
唯一性约束和唯一索引
不同数据库的实现不同,Oracle靠唯一索引实现唯一性,但是PostgreSQL两个都可以实现唯一性(似乎并无区别)。
约束和索引
前者用来检查数据的正确性,后者用来实现数据查询的优化,目的不同。
唯一性约束和唯一索引
在Oracle中,创建一个Constraint,同时也会创建一个该约束对应的唯一索引。创建唯一索引只会创建一个唯一索引,不会创建Constraint。也就是说 唯一性约束是通过创建唯一索引来实现的(Oracle)。
建表时加唯一性约束
1 | CREATE TABLE IF NOT EXISTS a_user ( |
给已建好的表加唯一性约束
1 | ALTER TABLE a_user add unique(account); |
区别
删除唯一性约束时可以只删除约束而不删除对应的索引,所以对应的列还是必须唯一;而删除了唯一索引的话就可以插入不唯一的值。(Oracle)
索引使用 create/drop index
创建和删除,而约束使用 alter table tableName add constraint
建立,使用 drop constraint
删除。
创建分区表
手动创建分区表(不推荐)
继承主表和添加限制
分区表继承主表,并且正常情况下都不要为这些分区表添加任何新的列。
重命名主表不影响继承关系
1 | CREATE TABLE a_user_1() inherits (a_user); |
分区表限制,决定了该表所能允许保存的数据集范围。这里必须保证各个分区表之间的限制不能有重叠。
1 | ALTER TABLE a_user_1 ADD CONSTRAINT a_user_1_sex_check_key CHECK (sex = 1); |
建表和限制一起
1 | create table a_user_1 ( CHECK (sex = 1) ) inherits (a_user); |
创建索引和约束
分区表上创建索引,该索引并不是严格必须创建的,但在大部分场景下,它都非常有用。
分表字段也应加索引,虽然这会命中所有记录
1 | CREATE UNIQUE INDEX idx_uk_a_user_1_account ON a_user_1 (account); |
继承关系修改
1 | alter table a_user_1 no inherit a_user; -- 删除继承 |
重定向插入数据(使用rule)
trigger和rule不同的是,触发器可以实现异常捕捉等实现更丰富的功能。
rule 不像 function,trigger一样独立存在的,而是依附于表上,当你把表删了,相应的rule就一起被删了。
创建规则
使用rule分流
1 | CREATE RULE a_user_rule_1 AS |
插入数据
1 | insert into a_user select * from a_user_all; |
查询
1 | SELECT * FROM a_user; |
删除继承关系
删除继承关系后,将不在能查到子表的数据。
若在 A 表上创建rule插入到 B 表,那么 B 不应再继承 A 表,否则会出现循环依赖,无法删除表的情况,当然这不是必须。
缺陷
1 | insert into a_user (id, account, name, sex, birthday, generation_time) |
执行上述sql发现,不符合规则的数据会插入主表中。实际应用中,主表不需要存储数据,而是希望将那些不满足规则的数据
1、直接丢弃
2、放到一张other表
3、创建一个新规则和新表以接收对应规则的数据
重定向插入数据(触发器)
定义一个trigger,把对主表的数据插入操作重定向到对应的分区表。
创建触发器
1 | CREATE TRIGGER trig_insert_a_user |
创建分区函数
1 | CREATE OR REPLACE FUNCTION func_insert_a_user() |
插入数据
1 | insert into a_user select * from a_user_all; |
查询
1 | SELECT * FROM a_user; |
缺陷
1 | insert into a_user (id, account, name, sex, birthday, generation_time) |
执行上述sql,此时不满足条件的数据丢弃,也可以使用other表接收这些数据。
需求:所有数据都应按照规律存到对应的子表(分区表)中,若不存在这样的表要实现自动新建。
重定向插入数据(触发器)-终极
创建触发器
1 | CREATE TRIGGER trig_insert_a_user |
创建分区函数
自动创建分区表并插入数据:
1 | CREATE OR REPLACE FUNCTION func_insert_a_user() |
插入数据
1 | insert into a_user select * from a_user_all; |
查询
1 | SELECT * FROM a_user; |
查询发现,不存在的表会自动新建,自此优化完成。
删除触发器
1 | SELECT * FROM pg_trigger; -- 列出触发器 |
执行计划分析
1 | EXPLAIN ( ANALYZE ON, buffers ON, costs ON, timing ON ) |
分表后的增删改查测试
新增数据
1 | insert into a_user (id, account, name, sex, birthday, generation_time) |
查询数据
如果想要查询父表的数据,忽略子表,可以使用 ONLY 关键字
1 | SELECT * FROM a_user T where T.account = 'zhangsan'; |
这里需要理解一个概念:给子表插入数据的时候,并不是同时把数据中的共享字段插入到父表中,只是简单通过继承关系使子表的数据在父表可见。如果你指定了 ONLY 关键字,则查询不在从子表中获取数据。
另外需要注意的是,由于继承表的本质原因,一些约束条件可能会被打破;例如,声明一个唯一字段,可能在查询结果中2条相同的值。因此,在使用的继承的过程中,你要特别注意约束;因为他们在各自的表中没有违反约束条件;因此,如果你在查询父表的时候没有制定 ONLY 字段,那它可能会返回你非预期的结果。
同理,update、delete同样可以使用 ONLY 关键字,示例:
1 | update only a_user set age = 1000 where account = 'zhangsan'; |
更新数据
1 | update a_user set age = 1000 where account = 'zhangsan'; |
下面语句执行失败,违反检查约束。因其原本就是根据sex分表,所以无法直接修改sex字段。只能删除后重新插入。
1 | update a_user set sex = 2 where account = 'zhangsan'; |
删除数据
1 | delete from a_user where account = 'zhangsan' |
其他
1 | select version(); |
注意事项
VACUUM
或 ANALYZE
a_user 只会对主表起作用,要想分析表,需要分别分析每个分区表。