论坛首页 综合技术论坛

postgres数据库优化(处理大表)

浏览 5004 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-02-27   最后修改:2009-02-27
   最近项目要改成网络版,这样原项目肯定不适合,特别是数据库方面,网络版用户会很多,检测到的数据会更多,估算了下,某些表可能超出表的最大容量,因此要对数据库进行优化。
   数据库优化主要包括包括对冗余字段的处理,提高查询性能和大表的处理,针对冗余字段,初步看了下,主要是有的字段根本没用到,这个可能是在原来设计的时候考虑太复杂,而现实项目中根本没有用,可以通过重新定义表,删除没有用的字段来处理。提高查询性能可通过建立相关索引,优化sql等手段达到目的。在这里主要对最后一个问题发表点自己的思路。
  谈到大表,会不自然的想到分区(拆分表),把一个表分成几个表来处理不就可以了。但我们的项目用的是postgres数据库,它有没有分区的功能?经过查资料,整理出一套方案。

  目前,PostgreSQL 支持通过表继承进行分区。 每个分区必须做为单独一个父表的子表进行创建。父表自身通常是空的; 它的存在只是为了代表整个数据集。

PostgreSQL 里面可以实现下面形式的分区:
范围分区
表被一个或者多个键字字段分区成"范围", 在这些范围之间没有重叠的数值分布到不同的分区里。 比如,我们可以为特定的商业对象根据数据范围分区,或者根据标识符范围分区。
列表分区
表是通过明确地列出每个分区里应该出现那些键字值实现的。

目前还不支持散列分区。

要设置一个分区的表,做下面的步骤:
创建"主表",所有分区都从它上面继承下去。
这个表将没有什么数据,不要在这个表上定义任何检查约束, 除非你希望约束同样也适用于所有分区。同时在其上定义任何索引或者唯一约束也没有意义。
创建几个"子"表,每个都从主表上继承。 通常,这些表将不会对从主表继承过来集合增加任何字段。
我们将把子表称作分区,尽管它们就是普通的 PostgreSQL 表。
给分区表增加约束,定义每个分区允许的健值。

CREATE TABLE test ( id int not null,
  logdate date not null );
每个分区都是拥有自己内容的完整的表,只是它们从 measurement 表继承定义。
这样就解决了我们的一个问题:删除旧数据。 每个月,我们需要做的只是在最旧的子表上执行一个 DROP TABLE, 然后为新月份创建一个新的子表。
我们必须增加非重叠的表约束,所以我们的建表脚本就变成:
CREATE TABLE test0801 ( CHECK (
  logdate >= DATE '2008-01-01' AND logdate < DATE '2008-02-01' ) )
INHERITS (test);
CREATE TABLE test0802 ( CHECK (
  logdate >= DATE '2008-02-01' AND logdate < DATE '2008-03-01' ) )
INHERITS (test);
......
我们可能还需要在键字字段上有索引:
CREATE INDEX test0801_logdate ON
  test0801(logdate);
CREATE INDEX test0802_logdate ON
  test0802(logdate);
......
我们选择先不建立更多的索引。
如果数据只进入最新的分区,我们可以设置一个非常简单的规则来插入数据。 我们必须每个月都重新定义这个规则,这样它总是指向当前分区。
(1。可以为用户做个界面,我们写好脚本,当子表的数据量达到一定数量的时候自动提醒管理员要创建新的子表了,这样管理员去手工点下创建新表,程序会创建新表并把相关的约束建好。
2。也可以创建触发器,当子表数达到一定量时自动触发创建子表或每个月初自动创建子表)
CREATE OR REPLACE RULE test_current_partition AS
  ON INSERT TO test DO INSTEAD INSERT INTO
test0802 VALUES ( NEW.id, NEW.logdate );
分区和约束排除

约束排除(Constraint exclusion)是一种查询优化技巧, 它改进了用上面方法定义的表分区的性能。比如:

SET constraint_exclusion = on; SELECT count(*) FROM
  test WHERE logdate >= DATE ‘2008-01-01′;
如果没有约束排除,上面的查询会扫描 measurement 表中的每一个分区。打开了约束排除之后,规划器将检查每个分区的约束然后试图证明该分区不需要被扫描,因为它不能包含任何符合 WHERE 子句条件的数据行。如果规划器可以证明这个,它就把该分区从查询规划里排除出去。

你可以使用 EXPLAIN 命令显示一个规划在 constraint_exclusion 打开和关闭情况下的不同。用上面方法设置的表的典型的缺省规划是:

SET constraint_exclusion = off; EXPLAIN SELECT count(*)
  FROM test WHERE logdate >= DATE ‘2006-01-01′;

部分或者全部分区可能会使用索引扫描而不是全表扫描, 不过这里要表达的意思是我们没有必要扫描旧的分区旧可以回答这个查询。 在我们打开约束排除之后,我们可以得到生成同样回答的明显节省的规划:

SET constraint_exclusion = on;
  EXPLAIN SELECT count(*) FROM test WHERE logdate >= DATE ‘2006-01-01′;
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics