当包含 WHERE 语句时,为什么这个查询要花这么长时间?

Why is this query taking so much longer when a WHERE statement is included?

对于那些对解释感兴趣的人

没有 WHERE:https://explain.depesz.com/s/XaDH

其中:https://explain.depesz.com/s/iPOL

我有一个视图,我可以 select * 在 519 毫秒内从中接收 500 多行,如果我添加 WHERE ordernumber = 165973(或任何订单号),则需要 18 秒。查询规划器还确信这两个查询都需要大约 18 秒,但如果没有 where 条件,它每次都会在大约 500 毫秒内完成。

CREATE VIEW v_recent_api_panels AS
  SELECT DISTINCT ON (s.barcode) s.barcode,
    s.ordernumber,
    production.machine_data_box(d.datastring) AS box,
    c."Edate",
    c."SDate",
    p.height,
    p.width,
    p.blankheight,
    p.blankwidth,
    p.paneltype,
    p.dateprocessed,
    p.listnum,
    p.material,
    p.color,
    p.boxnumber,
    p.location,
    p.cutout_param,
    s.lastmodified,
    p.machinetype,
    'NULL'::text AS status,
    (((((date_part('year'::text, p.danobatfab) || '-'::text) || date_part('month'::text, p.danobatfab)) || '-'::text) || date_part('day'::text, p.danobatfab)))::date AS danobatfab,
    p.fabdate AS originalfabdate
   FROM (((production.mv_recent_schedules s
     LEFT JOIN workorders.mv_recent_panel_details p ON ((p.barcode = s.barcode)))
     LEFT JOIN cupra.mv_parts c ON (((c."PrdRef")::text = s.barcode)))
     LEFT JOIN production.mv_machine_data d ON ((d.barcode = p.barcode)))
  WHERE (p.ordernumber IS NOT NULL)
  ORDER BY s.barcode;

编辑:我的 postgres 客户端(datagrip)在查询中添加了一个隐式的 LIMIT 500,只有在没有 WHERE 语句的情况下才能有效使用。
更改了这个问题的标题以反映我的发现。

编辑 2:我不知道我是否应该留下这个问题或删除它,因为它相当愚蠢,但答案是 select * 语句 LIMIT 500 只需要评估它遇到的前 500 行,但是 WHERE 强制它评估所有这些行。我的 sql 前辈正在添加限制,我在问这个问题时没有考虑到这一点。

肯定有错:快速执行计划显示执行时间为18秒。它还 returns 68489 行而不是 500 行。

问题出在你的函数上production.machine_data_box;它负责几乎所有的执行时间。

问题是函数总是对所有 271651 行求值,因为 WHERE 条件只能在视图的查询完成后应用,因为你使用 DISTINCT.

我有几个改进的想法:

  • 删除ORDER BY。它应该在使用视图的查询中。

  • 不要将 DISTINCT ON 放入视图中。然后你可以把它放入你的查询之后你的额外条件已经被评估,如果可能的话。

  • 将函数标记为昂贵 COST = 1000 或更高。然后优化器将更喜欢调用该函数的频率较低的计划。除非您摆脱 DISTINCT ON,否则这可能无济于事,但这肯定是正确的做法。

  • 如果可以,请重写函数,使其更快。

  • 升级到 PostgreSQL 9.6 或更高版本。 9.6 中有一个改进,将函数的评估推迟到排序之后。不确定这是否有帮助。