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

问题描述 投票:0回答:2

我有一个数据库“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;

这是我的触发点:

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

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

我多次尝试执行该查询后的结果,执行时间几乎相同。所以分区表并不能有效地更快地查看数据。
我的分区正确吗?

postgresql indexing partitioning postgresql-performance
2个回答
6
投票

200K 行并不是很多。

当您的完整表大于 RAM 时,分区主要有帮助,但大多数查询都可以从单个部分表中提供服务。


3
投票

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

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

巨大

并且查询主要在几个分区上,您可能会开始看到好处。小分区的索引要小得多,并且更容易装入 RAM(并保留在那里)。 充足的 RAM 是性能的关键因素(除了匹配索引之外)。 索引数量与读取性能几乎完全

无关

。一般准则是创建尽可能少的索引,但根据需要创建尽可能多的索引。如果有疑问,请优先选择可以服务更多类型查询的简单索引,而不是针对单个用例量身定制的高度专业化索引(除非该情况特别重要)。任何未使用的索引都只是写入性能的负担并浪费空间。 如果您最关心读取性能,单个大表上的部分索引

可能是一种替代方案。 旁白:你的触发功能可以在多个地方得到改进。从更易读的格式和这个提示开始:

PL/pgSQL 检查行是否存在 - SELECT INTO boolean

自我管理 PostgreSQL 分区表

© www.soinside.com 2019 - 2024. All rights reserved.