RGP*_*GPT 6 sql postgresql partitioning week-number
我可以想象按日期对表进行分区(特别是对日志进行分区)是一种广泛使用的方法,但是我找不到解决我问题的好方法。
我想按周创建一个表分区(记录数量大到每月都可以)。之所以要每周一次,是因为我需要算法的数据,该算法将在过程中查找日期。
我的问题是我希望它考虑周并使用“典型”方法来创建分区,所以我必须手动创建它。这样的事情。
CREATE TABLE measurement_y2013w01 (
CHECK ( logdate >= DATE '2013-01-07' AND logdate < DATE '2013-01-14' )
) INHERITS (measurement);
CREATE TABLE measurement_y2006w02 (
CHECK ( logdate >= DATE '2013-01-14' AND logdate < DATE '2013-01-21' )
) INHERITS (measurement);
...
Run Code Online (Sandbox Code Playgroud)
但是我希望它能自动完成。我不想为每个星期一个一个地创建分区。
我给命名的规则是yYYYYwWW来命名分区或开始datadYYYYMMDD。
我想在插入时使用类似以下的方法检查分区:
SELECT
nmsp_parent.nspname AS parent_schema,
parent.relname AS parent,
nmsp_child.nspname AS child,
child.relname AS child_schema
FROM pg_inherits
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
JOIN pg_namespace nmsp_parent ON nmsp_parent.oid = parent.relnamespace
JOIN pg_namespace nmsp_child ON nmsp_child.oid = child.relnamespace
Run Code Online (Sandbox Code Playgroud)
如果分区不存在,则在插入之前创建分区,但考虑到插入的记录数,这将导致效率低下。
我的另一种选择是每周运行一个外部进程来创建该分区,但是我试图避免这种情况。
对于我所缺少的,是否有更有效的解决方案,例如用于每月检查?
小智 5
好的,让我们创建一个函数来处理该问题!
CREATE OR REPLACE FUNCTION create_partition_measurement( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN SELECT
'CREATE TABLE measurement_' || TO_CHAR( d, 'YYYY_WW' ) || ' (
CHECK ( EXTRACT(YEAR FROM logdate) = EXTRACT(YEAR FROM TIMESTAMP ''' || d || ''') AND EXTRACT(WEEK FROM logdate) = EXTRACT(WEEK FROM TIMESTAMP ''' || d || ''') )
) INHERITS (measurement);'
FROM generate_series( $1, $2, '1 week' ) AS d LOOP
EXECUTE create_query;
END LOOP;
END;
$$
language plpgsql;
Run Code Online (Sandbox Code Playgroud)
这样,您现在可以调用类似
SELECT create_partition_measurement ('2015/02/08','2015/03/01');
Run Code Online (Sandbox Code Playgroud)
并创建分区。完成自动化的第一步。
我使用以下测试表在自己的数据库中测试了所有这些:
CREATE TABLE measurement (id INT NOT NULL PRIMARY KEY, id_user INT NOT NULL, logdate TIMESTAMP NOT NULL);
Run Code Online (Sandbox Code Playgroud)
使用上面的函数创建分区后,我能够:
这应该足够=)
现在,关于自动化创建过程。我每个月都会使用一个简单的cron脚本为我调用此函数,并使用几个监视脚本来确保一切正常进行。Cron看起来像这样:
0 0 1 * * /var/lib/postgresql/create_partitions.sh
Run Code Online (Sandbox Code Playgroud)
脚本将使用当前日期和当前日期+ 1个月运行命令。看起来像这样:
startDate=`date "+%Y/%m/%d"`
endDate=`date -u -d "+1 month -$(date +%d) days" "+%Y/%m/%d"
psql -U "$dbUser" -w -c "SELECT create_partition_measurement('$startDate','$endDate');"
Run Code Online (Sandbox Code Playgroud)
如果您需要在表中包括索引,PK,FK或帮助触发器使所有这些工作正常进行,请告诉我。
您可以使用date_trunc函数将数据值舍入到一周的第一天。对于分区命名,您可以使用YYWW年中的年份和周数:
CREATE TABLE measurement_1301 (
CHECK ( date_trunc( 'week', logdate )::date = DATE '2013-01-07') )
INHERITS (measurement);
CREATE TABLE measurement_1302 (
CHECK ( date_trunc( 'week', logdate )::date = DATE '2013-01-14') )
INHERITS (measurement);
CREATE TABLE measurement_1303 (
CHECK ( date_trunc( 'week', logdate )::date = DATE '2013-01-21') )
INHERITS (measurement);
-- Default partition:
CREATE TABLE measurement_default () INHERITS (measurement);
Run Code Online (Sandbox Code Playgroud)
对于分区名称生成使用to_char( logdate::date, 'YYWW'),如果您更喜欢yYYYYwWW:to_char( logdate::date, '"y"YYYY"w"WW')
要检查现有分区,您可以使用非常简单的查询:
SELECT relname FROM pg_class
WHERE relname ~ '^measurement_[0-9]{4}$'
ORDER BY RIGHT(relname,4) DESC
Run Code Online (Sandbox Code Playgroud)
如果给定周没有分区,数据路由触发器将插入到适当的分区并回退到默认值。
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF to_char( NEW.logdate::date, 'YYWW') = '1301' THEN
INSERT INTO measurement_1301 VALUES (NEW.*);
ELSIF to_char( NEW.logdate::date, 'YYWW') = '1302' THEN
INSERT INTO measurement_1302 VALUES (NEW.*);
ELSIF to_char( NEW.logdate::date, 'YYWW') = '1303' THEN
INSERT INTO measurement_1303 VALUES (NEW.*);
-- ...
ELSE
INSERT INTO measurement_default VALUES (NEW.*);
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER measurement_insert_tr BEFORE INSERT ON measurement
FOR EACH ROW EXECUTE PROCEDURE measurement_insert_trigger()
Run Code Online (Sandbox Code Playgroud)
您将提前创建所有分区。或者,您可以使用默认分区,并时不时地对存储在那里的数据进行重新分区,创建新分区并调整插入触发器。
PS您可以在此处找到基于触发器的分区解决方案的脚本http://hg.nowitworks.eu/postgresql-triggers-and-partitions
| 归档时间: |
|
| 查看次数: |
3661 次 |
| 最近记录: |