当我尝试创建临时表时,我遇到了性能问题。以下代码是plpgsql函数的一部分:
StartTime := clock_timestamp();
CREATE TEMP TABLE wo_tmp WITH (OIDS) AS
SELECT workorders1_.woid AS w_id, workorders1_.woid4seg AS w_id4seg
FROM common.workorders workorders1_
INNER JOIN common.lines lines2_ ON workorders1_.wolineid=lines2_.lineid
INNER JOIN common.products products2_ ON workorders1_.woprodid=products2_.prodid
INNER JOIN common.depts depts3_ ON lines2_.linedeptid=depts3_.deptid
WHERE workorders1_.wostatus='F'
AND workorders1_.wotypestatus = ANY ('{R,C,I,D}'::text[])
AND (p_deptid = 0 OR (depts3_.deptid = p_deptid AND ((p_deptid = 5 AND workorders1_.wosegid = 1) OR workorders1_.wosegid = 4)))
AND (p_lineid = 0 OR lines2_.lineid = p_lineid)
AND (p_prodid = 0 OR products2_.prodid = p_prodid)
AND (p_nrkokili = 0 OR workorders1_.wonrkokili = p_nrkokili)
AND (p_accepted = TRUE OR workorders1_.worjacceptstatus = 'Y')
AND workorders1_.wodateleaverr BETWEEN p_dfr AND p_dto
AND lines2_.status <> 'D';
CREATE INDEX wo_tmp_w_id_idx
ON wo_tmp USING btree (w_id ASC NULLS LAST);
CREATE INDEX wo_tmp_w_id4seg_idx
ON wo_tmp USING btree (w_id4seg ASC NULLS LAST);
EndTime := clock_timestamp();
Delta := extract('epoch' from EndTime)::bigint - extract('epoch' from StartTime)::bigint;
RAISE NOTICE 'Duration [0] in seconds=%', Delta;
这是explain analyze
报告:http://explain.depesz.com/s/uerF
这很奇怪,因为当我执行这个功能时,我会收到通知:Duration [0] in seconds=11
。我在不创建临时表的情况下检查查询,结果时间为~300ms
。
是否有可能将记录(~73k)插入临时表需要11秒?我可以加快速度吗?
答案 0 :(得分:2)
当您在函数中填充临时表时,您可以找到多个问题:
锁定问题 - 每个临时表都是包含系统目录中某些字段的表。密集创建和删除这些表会导致批量锁定的开销很大。有时临时表可以由数组替换。这不是你的情况,因为你需要一个索引。
盲目优化 - PlpgSQL函数中的嵌入式SQL针对大多数常见值进行了优化(这种机制在PostgreSQL 9.2中略有增强(但仍然存在可能的性能问题)。它没有针对当前值进行优化 - 这个事实可以强制执行某些性能问题。然后需要动态SQL。此问题的一些链接(one和second)
一些hw或文件系统问题 - 我对帮助WITHOUT OIDS
感到有些困惑。看起来您的文件系统对您来说是一个可怕的瓶颈。临时表存储在文件系统缓存中 - 存储53K行应该很快..删除4个字节(从35开始)不是太大的变化。
postgres=# create table t1 with (oids) as select 1 a,2 b,3 c from generate_series(1,73000);
SELECT 73000
Time: 302.083 ms
postgres=# create table t2 as select 1 a,2 b,3 c from generate_series(1,73000);
SELECT 73000
Time: 267.459 ms
postgres=# create temp table t3 with (oids) as select 1 a,2 b,3 c from generate_series(1,73000);
SELECT 73000
Time: 154.431 ms
postgres=# create temp table t4 as select 1 a,2 b,3 c from generate_series(1,73000);
SELECT 73000
Time: 153.085 ms
postgres=# \dt+ t*
List of relations
Schema | Name | Type | Owner | Size | Description
-----------+------+-------+-------+---------+-------------
pg_temp_2 | t3 | table | pavel | 3720 kB |
pg_temp_2 | t4 | table | pavel | 3160 kB |
public | t1 | table | pavel | 3720 kB |
public | t2 | table | pavel | 3160 kB |
(4 rows)
将3MB文件写入文件系统应该明显少于1秒..所以11秒的开销很奇怪。附:默认temp_buffers
是8MB,所以你的结果应该只存储在内存中 - 可能这个假设是假的 - 更可能的是盲优化假设。
答案 1 :(得分:1)
对于初学者,不要将WITH (OIDS)
用于临时表。永远。不鼓励在常规表中使用OID。这对于临时表来说是双倍的。还减少了磁盘上所需的RAM /空间,这可能是这里的主要瓶颈。切换到WITHOUT OIDS
。
接下来,一个可能的原因(有根据的猜测)是缺少临时缓冲区,这会迫使临时表溢出到磁盘。使用
检查临时表的实际大小SELECT pg_size_pretty(pg_relation_size('wo_tmp'));
并相应地设置temp_buffers
,可能仅用于会话 - 慷慨地整理,足以避免写入磁盘。
详细说明: