Grz*_*zes 16 postgresql server-configuration postgresql-performance
我必须通过调整基本的PostgreSQL服务器配置参数来优化查询.在文档中,我遇到了work_mem参数.然后我检查了如何更改此参数会影响我的查询的性能(使用sort).我用各种work_mem设置测量了查询执行时间,非常失望.
我执行查询的表包含10,000,000行,并且有430 MB的数据要排序.(Sort Method: external merge Disk: 430112kB).
用work_mem = 1MB,EXPLAIN输出是:
Total runtime: 29950.571 ms (sort takes about 19300 ms).
Sort (cost=4032588.78..4082588.66 rows=19999954 width=8)
(actual time=22577.149..26424.951 rows=20000000 loops=1)
Sort Key: "*SELECT* 1".n
Sort Method: external merge Disk: 430104kB
Run Code Online (Sandbox Code Playgroud)
用work_mem = 5MB:
Total runtime: 36282.729 ms (sort: 25400 ms).
Sort (cost=3485713.78..3535713.66 rows=19999954 width=8)
(actual time=25062.383..33246.561 rows=20000000 loops=1)
Sort Key: "*SELECT* 1".n
Sort Method: external merge Disk: 430104kB
Run Code Online (Sandbox Code Playgroud)
用work_mem = 64MB:
Total runtime: 42566.538 ms (sort: 31000 ms).
Sort (cost=3212276.28..3262276.16 rows=19999954 width=8)
(actual time=28599.611..39454.279 rows=20000000 loops=1)
Sort Key: "*SELECT* 1".n
Sort Method: external merge Disk: 430104kB
Run Code Online (Sandbox Code Playgroud)
谁能解释为什么性能会变差?或者建议任何其他方法通过更改服务器参数来加快查询执行速度?
我的查询(我知道它不是最优的,但我必须对这种查询进行基准测试):
SELECT n
FROM (
SELECT n + 1 AS n FROM table_name
EXCEPT
SELECT n FROM table_name) AS q1
ORDER BY n DESC;
Run Code Online (Sandbox Code Playgroud)
完整的执行计划:
Sort (cost=5805421.81..5830421.75 rows=9999977 width=8) (actual time=30405.682..30405.682 rows=1 loops=1)
Sort Key: q1.n
Sort Method: quicksort Memory: 25kB
-> Subquery Scan q1 (cost=4032588.78..4232588.32 rows=9999977 width=8) (actual time=30405.636..30405.637 rows=1 loops=1)
-> SetOp Except (cost=4032588.78..4132588.55 rows=9999977 width=8) (actual time=30405.634..30405.634 rows=1 loops=1)
-> Sort (cost=4032588.78..4082588.66 rows=19999954 width=8) (actual time=23046.478..27733.020 rows=20000000 loops=1)
Sort Key: "*SELECT* 1".n
Sort Method: external merge Disk: 430104kB
-> Append (cost=0.00..513495.02 rows=19999954 width=8) (actual time=0.040..8191.185 rows=20000000 loops=1)
-> Subquery Scan "*SELECT* 1" (cost=0.00..269247.48 rows=9999977 width=8) (actual time=0.039..3651.506 rows=10000000 loops=1)
-> Seq Scan on table_name (cost=0.00..169247.71 rows=9999977 width=8) (actual time=0.038..2258.323 rows=10000000 loops=1)
-> Subquery Scan "*SELECT* 2" (cost=0.00..244247.54 rows=9999977 width=8) (actual time=0.008..2697.546 rows=10000000 loops=1)
-> Seq Scan on table_name (cost=0.00..144247.77 rows=9999977 width=8) (actual time=0.006..1079.561 rows=10000000 loops=1)
Total runtime: 30496.100 ms
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 13
我在explain.depesz.com上发布了您的查询计划,看一看.
在某些地方,查询计划者的估计是非常错误的.你ANALYZE最近跑过吗?
阅读规划师和规划师成本常量使用的统计手册中的章节.要特别注意的章节random_page_cost和default_statistics_target.
我会尝试:
ALTER TABLE diplomas ALTER COLUMN number SET STATISTICS 1000;
ANALYZE diplomas;
Run Code Online (Sandbox Code Playgroud)
鉴于您的1000万行,您甚至可能会更高.这取决于您的数据分布和实际查询.实验.默认值为100,最大值 是10000.
对于该大小的数据库,work_mem通常只有1或5 MB的数据库是不够的.阅读@aleroot链接到的Tuning Postgres上的Postgres Wiki页面.
由于您的查询根据输出需要430104kB的内存EXPLAIN,您必须设置work_mem为500MB或更多以允许内存中排序.内存中的数据表示比磁盘上的表示需要更多的空间.您可能对Tom Lane最近发布的内容感兴趣.
work_mem如你所尝试的那样增加一点点,显然不会有太大帮助,甚至可能会放慢速度.不知道如何解释减速.也许附加功能SET LOCAL根本没有使用,或者只是最初使用,还不够,但是从其他内存分配中消失了.
如果您的记忆力有限,请不要设置ANALYZE太高,否则可能会使竞争资源匮乏.仅为此查询临时设置足够高:
SET work_mem = '500MB';
Run Code Online (Sandbox Code Playgroud)
之后将其重置为默认值:
RESET work_mem;
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,使用random_page_cost它来为当前事务设置它.无论哪种方式,最好在单个事务中运行所有这些.