分区表:从哪里开始?
Partitioning Tables: Where to Begin?
我有一个 table 有 1 亿行,而且它只会继续增长。
为了加快 select
查询速度,我想对这个 table 进行分区,最好的方法是什么?我以前 从未 分区过 table,我什至不知道从哪里开始。
我在最常用于 where
子句、group by
或 order by
的列上有索引。
编辑第 1 部分:
现在,我的 select 查询每个大约需要 55-60 秒,带有索引。
编辑第 2 部分:
我的 table 没有标准化到 3NF。它目前是一个 1NF 形式的巨人 table。 table 大约有 13 列,1 亿多行。
我 只有 在列上有索引,我用这些索引过滤我的 select 查询。
索引列的基数非常高,有许多不同的值(例如,电子邮件、员工编号、日期等)
编辑第 3 部分:
我看了 Mark 发布的 link,这是一个很好的参考,我只是对他们使用的功能有几个问题。
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
$$到底是什么意思?我在使用 SQL 之前从未创建过函数,并且是一般编程的新手。
当您使用 NEW.*
部分时,NEW
指的是输入的新值?它不是特定的 table 或任何东西,它只是正在输入的新行。您使用 "NEW" 来表示新行,对吗?我一直在试验这个,这是我得出的结论,但我只是想看看其他人的想法。
编辑第 4 部分:
$$ 显然用于指示您何时开始和结束函数。它还用于编写字符串常量。我是从 What are '$$' used for in PL/pgSQL
那里学到的
有很多方法可以对 table 进行分区,但您可以使用其他策略而不是分区,例如部分索引。很难向您提供任何建议,除非您包括 table 的架构、其中的数据示例、您通常 运行 的示例查询以及 EXPLAIN 的结果对该查询进行分析,了解 PostgreSQL 正在做什么以及影响在哪里。
第 1 部分
每次查询 55-60 秒通常被认为是 unacceptable。你有一些严肃的修复工作要做。
第 2 部分
规范化不一定是解决性能问题的要求或方法。这实际上取决于您获取和访问数据的方式。 13列根本不多,也不是1亿行。
在您不作为过滤依据的列上建立索引完全是一种浪费,所以您可以做到这一点。但是,在列上有索引并不能保证它会被使用:它取决于给定查询的规划器策略、数据的基数以及查询中过滤器 and/or 连接条件的种类。同样,有一个查询示例 运行 以及对该查询的解释分析对于提供任何有用的建议都是必不可少的。
第 3 部分
$$
是另一种引用形式。等价于单引号'
,但可以用单引号嵌套。函数是作为字符串创建的,创建带引号的函数需要转义(加倍)函数中的任何引号,如下所示:
CREATE OR REPLACE FUNCTION measurement_insert_trigger() RETURNS TRIGGER AS '
BEGIN
IF ( NEW.logdate >= DATE ''2006-02-01'' AND
NEW.logdate < DATE ''2006-03-01'' ) THEN
...
END;
' LANGUAGE plpgsql;
此外,像 PgAdmin3 这样具有语法高亮的编辑器会将整个字符串绘制为红色,而不是继续高亮正常的 SQL 语法。这就是 $$
的用途。此外,美元引号可以命名和嵌套,如下所示:
CREATE OR REPLACE FUNCTION tablecount(tablename text) RETURNS bigint AS $func$
DECLARE
_cnt bigint;
BEGIN
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = ) THEN
EXECUTE $exec$ SELECT COUNT(*) FROM $exec$||quote_ident() into _cnt;
END IF;
RETURN _cnt;
END;
$func$ LANGUAGE plpgsql;
NEW
和OLD
是RECORDS,在触发器中根据触发器的类型以及触发器是在更改前还是更改后执行,设置了旧值和新值。记录中的字段的访问方式与查询中 table 的别名访问它们的方式相同,例如NEW.id
.
您可以在 http://www.postgresql.org 中找到所有这些的详细解释。
我有一个 table 有 1 亿行,而且它只会继续增长。
为了加快 select
查询速度,我想对这个 table 进行分区,最好的方法是什么?我以前 从未 分区过 table,我什至不知道从哪里开始。
我在最常用于 where
子句、group by
或 order by
的列上有索引。
编辑第 1 部分: 现在,我的 select 查询每个大约需要 55-60 秒,带有索引。
编辑第 2 部分: 我的 table 没有标准化到 3NF。它目前是一个 1NF 形式的巨人 table。 table 大约有 13 列,1 亿多行。
我 只有 在列上有索引,我用这些索引过滤我的 select 查询。
索引列的基数非常高,有许多不同的值(例如,电子邮件、员工编号、日期等)
编辑第 3 部分: 我看了 Mark 发布的 link,这是一个很好的参考,我只是对他们使用的功能有几个问题。
CREATE OR REPLACE FUNCTION measurement_insert_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF ( NEW.logdate >= DATE '2006-02-01' AND
NEW.logdate < DATE '2006-03-01' ) THEN
INSERT INTO measurement_y2006m02 VALUES (NEW.*);
ELSIF ( NEW.logdate >= DATE '2006-03-01' AND
NEW.logdate < DATE '2006-04-01' ) THEN
INSERT INTO measurement_y2006m03 VALUES (NEW.*);
...
ELSIF ( NEW.logdate >= DATE '2008-01-01' AND
NEW.logdate < DATE '2008-02-01' ) THEN
INSERT INTO measurement_y2008m01 VALUES (NEW.*);
ELSE
RAISE EXCEPTION 'Date out of range. Fix the measurement_insert_trigger() function!';
END IF;
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
$$到底是什么意思?我在使用 SQL 之前从未创建过函数,并且是一般编程的新手。
当您使用 NEW.*
部分时,NEW
指的是输入的新值?它不是特定的 table 或任何东西,它只是正在输入的新行。您使用 "NEW" 来表示新行,对吗?我一直在试验这个,这是我得出的结论,但我只是想看看其他人的想法。
编辑第 4 部分: $$ 显然用于指示您何时开始和结束函数。它还用于编写字符串常量。我是从 What are '$$' used for in PL/pgSQL
那里学到的有很多方法可以对 table 进行分区,但您可以使用其他策略而不是分区,例如部分索引。很难向您提供任何建议,除非您包括 table 的架构、其中的数据示例、您通常 运行 的示例查询以及 EXPLAIN 的结果对该查询进行分析,了解 PostgreSQL 正在做什么以及影响在哪里。
第 1 部分
每次查询 55-60 秒通常被认为是 unacceptable。你有一些严肃的修复工作要做。
第 2 部分
规范化不一定是解决性能问题的要求或方法。这实际上取决于您获取和访问数据的方式。 13列根本不多,也不是1亿行。
在您不作为过滤依据的列上建立索引完全是一种浪费,所以您可以做到这一点。但是,在列上有索引并不能保证它会被使用:它取决于给定查询的规划器策略、数据的基数以及查询中过滤器 and/or 连接条件的种类。同样,有一个查询示例 运行 以及对该查询的解释分析对于提供任何有用的建议都是必不可少的。
第 3 部分
$$
是另一种引用形式。等价于单引号'
,但可以用单引号嵌套。函数是作为字符串创建的,创建带引号的函数需要转义(加倍)函数中的任何引号,如下所示:
CREATE OR REPLACE FUNCTION measurement_insert_trigger() RETURNS TRIGGER AS '
BEGIN
IF ( NEW.logdate >= DATE ''2006-02-01'' AND
NEW.logdate < DATE ''2006-03-01'' ) THEN
...
END;
' LANGUAGE plpgsql;
此外,像 PgAdmin3 这样具有语法高亮的编辑器会将整个字符串绘制为红色,而不是继续高亮正常的 SQL 语法。这就是 $$
的用途。此外,美元引号可以命名和嵌套,如下所示:
CREATE OR REPLACE FUNCTION tablecount(tablename text) RETURNS bigint AS $func$
DECLARE
_cnt bigint;
BEGIN
IF EXISTS (SELECT 1 FROM pg_class WHERE relname = ) THEN
EXECUTE $exec$ SELECT COUNT(*) FROM $exec$||quote_ident() into _cnt;
END IF;
RETURN _cnt;
END;
$func$ LANGUAGE plpgsql;
NEW
和OLD
是RECORDS,在触发器中根据触发器的类型以及触发器是在更改前还是更改后执行,设置了旧值和新值。记录中的字段的访问方式与查询中 table 的别名访问它们的方式相同,例如NEW.id
.
您可以在 http://www.postgresql.org 中找到所有这些的详细解释。