PostgreSQL 查询随机执行需要几分钟

Posted

技术标签:

【中文标题】PostgreSQL 查询随机执行需要几分钟【英文标题】:PostgreSQL queries randomly takes minutes to execute 【发布时间】:2018-01-03 12:10:51 【问题描述】:

当多次(按顺序)运行同一个 SELECT 查询时,大约 10% 的查询需要几分钟才能执行(3 到 20 分钟)。 所有其他人在大约 100 毫秒内执行。 当长时间查询运行时,postgreSQL 进程占用 100% cpu。

我们在 Debian GNU/Linux 8.7 (jessie) 上运行 postgreSQL v9.4。 每天都会在数据库上运行 VACUUM ANALYZE。

在服务器端启用日志记录后,我们会看到以下条目:

成功场景:

2018-01-02 21:41:56 CET [15948]: [13776-1] STATEMENT:  BEGIN
2018-01-02 21:41:56 CET [15948]: [13777-1] LOG:  rewritten parse tree:
2018-01-02 21:41:56 CET [15948]: [13778-1] DETAIL:  (
        ... )
2018-01-02 21:41:56 CET [15948]: [13779-1] STATEMENT:  BEGIN
2018-01-02 21:41:56 CET [15948]: [13780-1] LOG:  duration: 0.114 ms  parse <unnamed>: BEGIN
2018-01-02 21:41:56 CET [15948]: [13781-1] LOG:  duration: 0.010 ms  bind <unnamed>: BEGIN
2018-01-02 21:41:56 CET [15948]: [13782-1] LOG:  execute <unnamed>: BEGIN
2018-01-02 21:41:56 CET [15948]: [13783-1] LOG:  duration: 0.015 ms
2018-01-02 21:41:56 CET [15948]: [13797-1] LOG:  plan:
2018-01-02 21:41:56 CET [15948]: [13798-1] DETAIL:     PLANNEDSTMT 
        ...
2018-01-02 21:41:56 CET [15948]: [13799-1] STATEMENT:  select 
        ... (the SELECT query)
2018-01-02 21:41:56 CET [15948]: [13800-1] LOG:  duration: 10.303 ms  bind S_21/C_24: select 
        ... (the SELECT query again)
2018-01-02 21:41:56 CET [15948]: [13801-1] DETAIL:  parameters: $1 = '149', $2 = '6'...(the query parameters)
2018-01-02 21:41:56 CET [15948]: [13802-1] LOG:  execute S_21/C_24: select 
        ... (the SELECT query again)
2018-01-02 21:41:56 CET [15948  ]: [13803-1] DETAIL:  parameters: $1 = '149', $2 = '6'...(the query parameters again)
2018-01-02 21:41:56 CET [15948]: [13804-1] LOG:  duration: 15.662 ms

失败的场景(长时间查询):

2018-01-02 21:36:55 CET [15741]: [13060-1] STATEMENT:  BEGIN
2018-01-02 21:36:55 CET [15741]: [13061-1] LOG:  rewritten parse tree:
2018-01-02 21:36:55 CET [15741]: [13062-1] DETAIL:  (
        ... )
2018-01-02 21:36:55 CET [15741]: [13063-1] STATEMENT:  BEGIN
2018-01-02 21:36:55 CET [15741]: [13064-1] LOG:  duration: 0.107 ms  parse <unnamed>: BEGIN
2018-01-02 21:36:55 CET [15741]: [13065-1] LOG:  duration: 0.009 ms  bind <unnamed>: BEGIN
2018-01-02 21:36:55 CET [15741]: [13066-1] LOG:  execute <unnamed>: BEGIN
2018-01-02 21:36:55 CET [15741]: [13067-1] LOG:  duration: 0.016 ms
2018-01-02 21:36:55 CET [15741]: [13081-1] LOG:  plan:
2018-01-02 21:36:55 CET [15741]: [13082-1] DETAIL:     PLANNEDSTMT 
        ...
2018-01-02 21:36:55 CET [15741]: [13083-1] STATEMENT:  select 
        ... (the SELECT query)
2018-01-02 21:36:55 CET [15741]: [13084-1] LOG:  duration: 9.886 ms  bind S_20/C_27: select 
        ... (the SELECT query again)
2018-01-02 21:36:55 CET [15741]: [13085-1] DETAIL:  parameters: $1 = '149', $2 = '6'...(the query parameters)
2018-01-02 21:36:55 CET [15741]: [13086-1] LOG:  execute S_20/C_27: select 
    ... (the SELECT query again)
2018-01-02 21:36:55 CET [15741]: [13087-1] DETAIL:  parameters: $1 = '149', $2 = '6'...(the query parameters again)

**/!\--- LOOPING ABOUT 150 times ---/!\**
        2018-01-02 21:42:23 CET [15741]: [13088-1] LOG:  temporary file: path "base/pgsql_tmp/pgsql_tmp15741.XX", size 9498636 (this value changes at every loop)
        2018-01-02 21:42:23 CET [15741]: [13089-1] STATEMENT:  select 
            ... (the SELECT query again)
**/!\--- END LOOP ---/!\**

2018-01-02 21:46:19 CET [15741]: [13340-1] LOG:  duration: 563668.493 ms
2018-01-02 21:46:19 CET [15741]: [13341-1] LOG:  duration: 0.026 ms  bind S_2: COMMIT
2018-01-02 21:46:19 CET [15741]: [13342-1] LOG:  execute S_2: COMMIT
2018-01-02 21:46:19 CET [15741]: [13343-1] LOG:  duration: 0.155 ms
2018-01-02 21:46:19 CET [15741]: [13344-1] LOG:  disconnection: session time: 0:10:23.538 user=xxx database=yyy host=127.0.0.1 port=60880                    

查看执行计划时,我们看到: - 所有 OK 查询都有相同的计划 - 所有 NOK(长期)查询都有相同的计划 - OK 和 NOK 计划略有不同:

        'total_cost' values (near but different values)
        ...
        TARGETENTRY 
            :expr 
                VAR 
                :varno 65000 ---------> differs
                :varattno 3  ---------> differs
                :vartype 20 
                :vartypmod -1 
                :varcollid 0 
                :varlevelsup 0 
                :varnoold 10  ---------> differs
                :varoattno 1 
                :location 2459 ---------> differs
                
        ... 
        :args (...
        PARAM | RELABELTYPE | CONST ---------> differs, always CONST for OK queries, always PARAM | RELABELTYPE for NOK queries
        ...
        

添加了其他信息: - Autovacuum 已关闭(每晚安排一次) - pg_stat_reset() 已运行 + ANALYZE(pbm 仍然存在) - 主表统计数据已增加 (500),但 pbm 仍然存在。

此 pbm 出现在 Alfresco (5.1g) 环境中(使用 alfresco seach API),但我们无法通过直接 sql 查询重现此 pbm。

为这样的 SELECT 查询使用这么多临时文件有意义吗?

查询:

select
node.id as id 
from alf_node node 
where node.type_qname_id <> 149 
AND node.store_id = 6 
AND ( 
node.id IN 
    (
    select aspect.node_id 
    from alf_node_aspects aspect 
    where aspect.qname_id IN ( 260 )
    ) 
AND node.id IN 
    (
    select PROP.node_id 
    from alf_node_properties PROP 
    where (249 = PROP.qname_id) 
        AND PROP.string_value = 'Mandats' 
    ) 
AND node.id IN 
    (
    select PROP.node_id 
    from alf_node_properties PROP 
    where (245 = PROP.qname_id) 
        AND PROP.string_value = '1' 
    ) 
AND node.id IN 
    (
    select PROP.node_id 
    from alf_node_properties PROP 
    where (247 = PROP.qname_id) 
        AND PROP.string_value = '869637' 
    ) 
AND node.id IN 
    (
    select PROP.node_id 
    from alf_node_properties PROP 
    where (248 = PROP.qname_id) 
        AND PROP.string_value = 'AGF00619' 
    )
) 
order by node.audit_modified DESC;

有什么建议吗? 谢谢, 文森特

【问题讨论】:

也许还有其他查询锁定了您的 SELECT 需要的东西? 这个临时文件是什么,为什么它会增长? (对于 SELECT 语句?) 所以你有一个准备好的(动态?)查询,你重复调用。是否存在使用相同表的并发会话? autovacuum 正在运行吗?表(或:索引)是否包含很多死行?也许您应该将查询添加到您的帖子中。 这个临时文件是什么,为什么它会增长? (对于 SELECT 语句?):好问题,我不知道... 【参考方案1】:

你试过了吗?:select pg_stat_reset();

【讨论】:

不,我认为这是由 VACCUM ANALYSE 完成的。不是吗?另一种选择是增加表的统计级别?

以上是关于PostgreSQL 查询随机执行需要几分钟的主要内容,如果未能解决你的问题,请参考以下文章

pgAdmin 4 在查询执行后不显示结果(postgreSQL)

提高 PostgreSQL 函数性能

几乎相同的 PostgreSQL 查询相差 1 分钟?

PostgreSQL 分组错误

Twilio WebRTC TURN 中继在几分钟后随机停止工作

SQL语句优化,使用postgresql数据库,查询下面sql,需要20多分钟: