代码之家  ›  专栏  ›  技术社区  ›  rRr

在同一个DB表上执行2次几乎相同的选择所需的时间截然不同

  •  1
  • rRr  · 技术社区  · 7 年前

    对于圣诞节,我有一个问题,我真的很想找到如何处理的线索。。

    我有一个报告数据库,它由许多小型机器上的卫星数据库中的数据填充。每个卫星数据库每20分钟平均执行一次数据提取。他们使用相同的脚本。然而,它们安装在不同的装置上,分布在全国各地。

    现在我有一个SELECT,pentaho reporting使用它在这个report DB中的同一个DB表上执行。虽然一个选择需要毫秒才能执行,但另一个选择需要数小时。它们都在同一个表上执行,在同一个硬件上运行的同一个DB中。

    快速一号:

    SELECT
     res.ticket_id,
     res.entry_zone,
     res.entry_time,
     res.exit_time,
     res.parking_time,
     res.cost,
     co.org_name,
     cu.firstname,
     cu.surname,
     a.name AS article_name,
     res.car_id 
    FROM (SELECT
     lh.ticket_id,
     z.name AS entry_zone,
     lh.park_entered AS entry_time,
     lh.park_leaved AS exit_time,
     interval_to_hourminsec(lh.park_leaved - lh.park_entered) AS parking_time,
     lh.cost,
     lh.article_id,
     sa.contrib_user_id,
     fpl.car_id
     FROM longterm_history lh, zones z, sold_articles sa, flexcore_passing_log fpl
     WHERE lh.park_leaved BETWEEN  '2017-12-18 00:00' AND  '2017-12-19 23:59'
     AND sa.ticket_id = lh.ticket_id
     AND lh.entry_zone = z.zone_number
     AND lh.passlog_id = fpl.id
     AND lh.park_uuid = 100068
     AND z.park_uuid = 100068
     AND sa.park_uuid = 100068
     AND fpl.park_uuid = 100068
     AND lh.entry_zone = 1
    ) AS res 
    LEFT OUTER JOIN articles a ON res.article_id = a.article_id AND a.park_uuid = 100068 
    LEFT OUTER JOIN cont_users cu ON res.contrib_user_id = cu.id AND cu.park_uuid = 100068 
    LEFT OUTER JOIN cont_orgs co ON cu.org_id = co.id AND co.park_uuid = 100068 
    ORDER BY res.exit_time ASC
    

    慢速:

    SELECT
     res.ticket_id,
     res.entry_zone,
     res.entry_time,
     res.exit_time,
     res.parking_time,
     res.cost,
     co.org_name,
     cu.firstname,
     cu.surname,
     a.name AS article_name,
     res.car_id 
    FROM (SELECT
     lh.ticket_id,
     z.name AS entry_zone,
     lh.park_entered AS entry_time,
     lh.park_leaved AS exit_time,
     interval_to_hourminsec(lh.park_leaved - lh.park_entered) AS parking_time,
     lh.cost,
     lh.article_id,
     sa.contrib_user_id,
     fpl.car_id
     FROM longterm_history lh, zones z, sold_articles sa, flexcore_passing_log fpl
     WHERE lh.park_leaved BETWEEN  '2017-12-18 00:00' AND  '2017-12-19 23:59'
     AND sa.ticket_id = lh.ticket_id
     AND lh.entry_zone = z.zone_number
     AND lh.passlog_id = fpl.id
     AND lh.park_uuid = 100146
     AND z.park_uuid = 100146
     AND sa.park_uuid = 100146
     AND fpl.park_uuid = 100146
     AND lh.entry_zone = 1
    ) AS res 
    LEFT OUTER JOIN articles a ON res.article_id = a.article_id AND a.park_uuid = 100146 
    LEFT OUTER JOIN cont_users cu ON res.contrib_user_id = cu.id AND cu.park_uuid = 100146 
    LEFT OUTER JOIN cont_orgs co ON cu.org_id = co.id AND co.park_uuid = 100146 
    ORDER BY res.exit_time ASC
    

    如何找出问题所在,是什么导致第二次选择在小时内执行?

    我使用的是postgres SQL,服务器版本是9.6.3 通过pentaho数据集成将数据提取到数据库中


    编辑:

    通过运行两个查询后 EXPLAIN (ANALYZE, BUFFERS) 最大的显著区别在于这一部分:

                                               ->  Bitmap Index Scan on longterm_history_park_uuid_idx  (cost=0.00..7609.82 rows=352718 width=0) (actual time=492.753..492.753 rows=354537 loops=1)
                                                     Index Cond: (park_uuid = 100068)
                                                     Buffers: shared read=1238
    
                                               ->  Bitmap Index Scan on longterm_history_park_uuid_idx  (cost=0.00..453.11 rows=20890 width=0) (actual time=4.680..4.680 rows=40021 loops=466475)
                                                     Index Cond: (park_uuid = 100146)
                                                     Buffers: shared hit=65306361 read=139
    

    看来第二次选择速度较慢的原因是 loops=466475 而不是 loops=1 dne按第一选择。但我不知道这意味着什么,也不知道如何修复它。。


    编辑2:

    我发现tootl可以在线共享计划,以下是链接:

    快速查询: https://explain.depesz.com/s/oYQLB

    慢速查询: https://explain.depesz.com/s/uOtf

    快速执行慢速查询,而回迁处于关闭状态: https://explain.depesz.com/s/4h4F

    1 回复  |  直到 7 年前
        1
  •  1
  •   rRr    7 年前

    问题已解决。

    学习阅读后 EXPLAIN ANALYZE 借助大量基于web的工具以图形方式显示,我注意到第二个(较慢的)select正在执行大量循环,优化器期望返回的行数少于实际返回的行数。

    这是优化器计算所基于的错误数据的迹象。为了解决这个问题,我跑了 VACUUM ANALYZE 在整个DB上。

    结果是性能显著提高,查询执行时间缩短 从4265437.080 ms 至547.202毫秒。