PostgreSQL的分区功能
分区是什么意思
這是將一個邏輯上的大表格,在物理上分成小的分區。
分割有”表格間的分割”和”節點間的分割”兩種,但是這次我們專門研究了表格間的分割,所以這裡將對此進行總結。
桌子之间的分割
使用触发器将数据存储到每个子表(分区)中,从应用程序的角度来看,这些子表看起来像一个表。

优点
– 通过分割来缩小搜索范围,提高处理效率。
– 可以批量删除分区(drop table)。
– 能够有效利用缓存。
缺点
由于使用触发器将插入操作分发到子表中,插入性能会变差。
分割方式
分割方法有两种,一种是水平分割,另一种是垂直分割。
-
- 水平分割是将表格的每一行分散到各自的分区的方法。可以根据用户的地址将其分割到每个省份的分区,或者按创建的月份进行分割。
垂直分割是将表格的一部分提取到分区的方法。只提取使用频率低的列或者非常大的列。
切割標準
在进行分割时,使用分割键来确定如何进行分割的音是分割的准则,可以分为“范围分割”、“列表分割”和“哈希分割”这三种类型。
-
- Range Partitioning: 根据分割键的值是否在范围内进行分割。
-
- List Partitioning: 根据分割键的值是否存在于列表中进行分割。
- Hash Partitioning: 根据哈希函数的值决定是否将其包含在分区中。
实际尝试一下
我将参考下面链接中的文件进行操作。
https://www.postgresql.jp/document/9.4/html/ddl-partitioning.html
创建一张桌子
首先创建主表(父表)。
CREATE TABLE measurement (
city_id int not null,
logdate date not null,
peaktemp int,
unitsales int
);
创建各自的分区(子表)
这次我们将为每个月份创建分区。(在文档中进行了一些修改)
CREATE TABLE measurement_y2016m12 (
CHECK ( logdate >= DATE '2016-12-01' AND logdate < DATE '2017-01-01' )
) INHERITS (measurement);
CREATE TABLE measurement_y2016m11 (
CHECK ( logdate >= DATE '2016-11-01' AND logdate < DATE '2016-12-01' )
) INHERITS (measurement);
CREATE TABLE measurement_y2016m10 (
CHECK ( logdate >= DATE '2016-10-01' AND logdate < DATE '2016-11-01' )
) INHERITS (measurement);
我們創建的這個表繼承於measurement(主表),所以結構是相同的。
此外,我們在每個表上都使用CHECK來進行日期約束。
改变设置
给它添加索引
CREATE INDEX measurement_y2016m12_logdate ON measurement_y2016m12 (logdate);
CREATE INDEX measurement_y2016m11_logdate ON measurement_y2016m11 (logdate);
CREATE INDEX measurement_y2016m10_logdate ON measurement_y2016m10 (logdate);
创建一个函数并设置触发器。
如果您想要将数据放入全新的分区,请按照以下方式进行设置。
--関数の作成
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO measurement_y2016m12 VALUES (NEW.*);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
-- トリガの作成
CREATE TRIGGER insert_measurement_trigger
BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger();
处理数据
设置触发器,插入已设置的12月份数据。
INSERT INTO measurement(city_id, logdate, peaktemp, unitsales) VALUES(1, '2016-12-01', 20, 1000);
-- INSERT 0 0
SELECT * FROM measurement;
SELECT * FROM measurement_y2016m12;
插入值变成0,这是因为在内部取消了原始的插入操作,并对分区进行了另一个插入操作,所以显示为0。
选择操作可以进行,触发器可以很好地进行分配。
插入未设置触发器的数据。
只考虑12月份的数据尚未包含在内。
如果加入11月的数据,会产生什么结果呢?
INSERT INTO measurement(city_id, logdate, peaktemp, unitsales) VALUES(1, '2016-11-01', 20, 1000);
ERROR: new row for relation "measurement_y2016m12" violates check constraint "measurement_y2016m12_logdate_check"
DETAIL: Failing row contains (1, 2016-11-01, 20, 1000).
CONTEXT: SQL statement "INSERT INTO measurement_y2016m12 VALUES (NEW.*)"
PL/pgSQL function measurement_insert_trigger() line 3 at SQL statement
这次果然出了错误。
11月的数据也分配到了12月的表中,看起来被检查的约束排斥了。
在设置分区时,必须注意输入的数据是什么样的。
总结
我认为,根据文件设置本身非常易懂。但是,最好测量一下处理效率的提升程度。