表分区与包含许多索引的非分区表

时间:2015-01-12 04:15:42

标签: postgresql indexing partitioning postgresql-performance

我有一个DB“DB_One”,主表名为t_d_gate_out,上面有8个索引。我创建了另一个带有分区t_d_gate_out的数据库(我们称之为“DB_Two”)。它按月和年分隔(子表的示例:t_d_gate_out09-2013),它有两个索引(d _gate_out和每个子项的新列:i_trx_own

这是我创建和插入子表的功能:

CREATE OR REPLACE FUNCTION ctm_test.gateout_partition_function()
  RETURNS trigger AS
$BODY$ 
DECLARE new_time text;
tablename text;
seqname text;
seqname_schema text;
bulantahun text;
bulan text;
bulan2 text;
tahun text;
enddate text;
result record;

BEGIN new_time := to_char(NEW.d_gate_out,'MM-YYYY');
bulan:=to_char(NEW.d_gate_out,'MM');
bulan2:=extract(month from NEW.d_gate_out);
tahun:=to_char(NEW.d_gate_out,'YYYY');
bulantahun := new_time;
tablename := 't_d_gate_out'||bulantahun;
seqname := 't_d_gate_out'||bulantahun||'_seq';
seqname_schema := 'ctm_test.t_d_gate_out'||bulantahun||'_seq';

PERFORM 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE 

c.relkind = 'r' AND c.relname = tablename AND n.nspname = 'ctm_test';

IF NOT FOUND THEN  EXECUTE 'CREATE TABLE ctm_test.' || quote_ident(tablename) || ' ( i_trx_own 

serial PRIMARY KEY, CHECK (extract(month from d_gate_out)=' || bulan2 || ' AND extract(year from 

d_gate_out)=' || tahun || ')) INHERITS (ctm_test.t_d_gate_out)';

EXECUTE 'ALTER TABLE ctm_test.' || quote_ident(tablename) || ' OWNER TO postgres'; EXECUTE 'GRANT 

ALL ON TABLE ctm_test.' || quote_ident(tablename) || ' TO postgres';

 EXECUTE 'CREATE INDEX ' || quote_ident(tablename||'_indx1') || ' ON ctm_test.' || quote_ident

(tablename) || ' (i_trx_own);CREATE INDEX ' || quote_ident(tablename||'_indx2') || ' ON ctm_test.' || quote_ident

(tablename) || ' (d_gate_out)'; END IF;

EXECUTE 'INSERT INTO ctm_test.' || quote_ident(tablename) || ' VALUES ($1.*)' USING NEW; RETURN 

NULL; END; $BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION ctm_test.gateout_partition_function()
  OWNER TO postgres;

这是我的TRIGGER:

CREATE TRIGGER gateout_master_trigger
  BEFORE INSERT
  ON ctm_test.t_d_gate_out
  FOR EACH ROW
  EXECUTE PROCEDURE ctm_test.gateout_partition_function();

插入大约200k行后,我试图比较这两个DB之间查看数据的速度。我用来比较的查询:

select * from ctm_test."t_d_gate_out"
where d_gate_out BETWEEN '2013-10-01' AND '2013-10-31'

我尝试多次执行该查询后的结果,执行时间 ALMOST THE SAME 。因此,分区表无法更快地查看数据 我是否正确地进行了分区?

2 个答案:

答案 0 :(得分:2)

只要您的每个查询都可以使用索引,它们的执行情况几乎相同。 (实际上,您应该在分区表上看到顺序扫描,因为您从中读取了所有行。)
通过索引访问很快(我希望位图索引扫描)。单片表上的索引(更大)(并且还需要一个额外的前导列),这可能会挑战您的RAM大小,并且第一次运行将花费更多。但是只要索引驻留在RAM中并且你有足够的数量,你就不会注意到进一步的调用。在其他情况下,您可能从分区中获得更多利润。

或者更糟糕的是:涉及多个分区的查询往往比单个大表上的等效查询 更慢 。访问单个表会更便宜。对于像您演示的查询通常不是:在较小的时间范围内,仅跨越一个(或几个)分区。最糟糕的情况是从整个范围读取行的查询,随机展开。

如果您的表巨大并且查询主要位于几个分区上,您可能会开始看到一个好处。小分区的索引要小得多,而且更容易适应RAM(并保留在那里)。 大量RAM 是性能的关键因素(除了匹配索引)。

索引数对于读取性能几乎完全无关。一般准则是尽可能少地创建索引,但需要尽可能多的索引。如果有疑问,支持简单的索引,这些索引可以针对高度专业化的索引提供更多种类的查询,针对单个用例量身定制(除非这种情况特别重要)。任何未使用的索引只会影响写入性能并浪费空间。

如果您最关心的是阅读效果,那么单个大表上的partial indexes可能是另一种选择。

除此之外:您的触发功能可以在多个地方得到改善。从更易读的格式开始,这个提示:

带触发功能的相关答案:

答案 1 :(得分:2)

200K行不是很多。

当您的表大于RAM时,分区主要有用。您可以从一个表格中提供大部分查询。