Postgresql 表分区与具有多个索引的非分区表

Postgresql 表分区与具有多个索引的非分区表,postgresql,indexing,partitioning,postgresql-performance,Postgresql,Indexing,Partitioning,Postgresql Performance,我有一个DB“DB_One”,它有一个名为t_d_gate_out的主表,上面有8个索引。我用分区的t_d_gate_out创建了另一个数据库(我们称之为“DB_Two”)。它是按月份和年份划分的(子表的示例:t\u-d\u-gate\u-out09-2013),它有两个索引(d\u-gate\u-out和每个子表上的新列:i\u-trx\u-own) 这是我创建和插入子表的功能: CREATE OR REPLACE FUNCTION ctm_test.gateout_partition_fun

我有一个DB“DB_One”,它有一个名为
t_d_gate_out
的主表,上面有8个索引。我用分区的
t_d_gate_out
创建了另一个数据库(我们称之为“DB_Two”)。它是按月份和年份划分的(子表的示例:
t\u-d\u-gate\u-out09-2013
),它有两个索引(d
\u-gate\u-out
和每个子表上的新列:
i\u-trx\u-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;
这是我的扳机:

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行之后,我试图比较这两个数据库之间查看数据的速度。我用来比较的查询:

select * from ctm_test."t_d_gate_out"
where d_gate_out BETWEEN '2013-10-01' AND '2013-10-31'
结果是,在我多次尝试执行该查询之后,执行时间几乎相同。因此,分区表无法更快地查看数据。

分区是否正确?

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

或者更糟:涉及多个分区的查询往往比单个大表上的等效查询要慢。一张桌子更便宜。通常情况下,对于您演示的查询,情况并非如此:在较小的时间范围内,仅跨越一个(或几个)分区。最坏的情况是从整个范围中随机读取行的查询

如果您的表很大,并且查询主要集中在几个分区上,您可能会开始看到好处。一个小分区的索引要小得多,并且更容易放入RAM中(并保持不变)充足的RAM是性能的关键因素(除了匹配的索引)

索引的数量与读取性能几乎完全不相关。一般的指导原则是创建尽可能少的索引,但根据需要创建尽可能多的索引。如果有疑问,可以选择简单索引,它可以为更多类型的查询服务,而不是为单个用例定制的高度专业化索引(除非这种情况特别重要)。任何未使用的索引都会对写性能造成负担,并浪费空间

如果您最关心的是读取性能,那么在一个大表上进行读取可能是另一种选择

旁白:您的触发功能可以在多个地方得到改进。从可读性更强的格式开始,并给出以下提示:

与触发功能相关的答案:


    • 20万行不是很多


      分区主要在表大于RAM时提供帮助。您的大多数查询都可以从一个表中获得。

      200k并不是那么多,我们在一个月的分区中每天要处理大约2000万条记录,因此每个表分区有4.5亿到5亿条记录。谢谢,先生。我不太了解这个分区。我可以通过在主表上选择查询来获取子数据。我的意思是,当我执行时:从master_表中选择*,其中日期介于“2013-10-01”和“2013-11-31”之间。数据是从主表还是从子表中选取的?我仍然对这个分区的工作感到困惑。我只知道这是使数据库变得更轻的一种方法…:(如果我想按月份和年份划分分区,我是否正确地创建了我的“CHECK”?谢谢先生:)–因为您使用继承(
      INHERITS(ctm_test.t_d_gate_out)进行分区
      ,来自所有子表的数据都包含在主表的
      SELECT
      查询中。使用
      SELECT…from ONLY tbl
      排除子表:。检查约束:虽然正确,但效率非常低。请先以可读格式显示代码。我的“检查”工作原理如下:当我插入一行d_gate_out='2013-10-01'时,检查将是:检查(摘录(从d_gate_out开始的月份)='10'和摘录(从d_gate_out开始的年份)='2013')我的语法写对了吗??:)谢谢先生。我不太了解这个分区。我可以通过在主表上选择查询来获取子数据。我的意思是,当我执行时:从master_表中选择*,其中日期介于“2013-10-01”和“2013-11-31”之间。数据是从主表还是从子表中选取的?我仍然对这个分区的工作感到困惑。我只知道这是使数据库变得更轻的一种方法…:(如果我想按月份和年份划分分区,我是否正确地创建了我的“支票”?,谢谢先生:)