- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
今天我花了一个多小时来思考一个我无法理解的查询计划。查询是一个 UPDATE
,它根本不会运行。完全陷入僵局:pg_locks
表明它也没有等待任何事情。现在,我不认为自己是最好或最差的查询计划阅读器,但我发现这本书特别难。我想知道如何阅读这些内容?Pg aces 是否遵循一种方法来查明错误?
我打算再问一个关于如何解决这个问题的问题,但现在我要专门谈谈如何阅读这些类型的计划。
QUERY PLAN
--------------------------------------------------------------------------------------------
Nested Loop Anti Join (cost=47680.88..169413.12 rows=1 width=77)
Join Filter: ((co.fkey_style = v.chrome_styleid) AND (co.name = o.name))
-> Nested Loop (cost=5301.58..31738.10 rows=1 width=81)
-> Hash Join (cost=5301.58..29722.32 rows=229 width=40)
Hash Cond: ((io.lot_id = iv.lot_id) AND ((io.vin)::text = (iv.vin)::text))
-> Seq Scan on options io (cost=0.00..20223.32 rows=23004 width=36)
Filter: (name IS NULL)
-> Hash (cost=4547.33..4547.33 rows=36150 width=24)
-> Seq Scan on vehicles iv (cost=0.00..4547.33 rows=36150 width=24)
Filter: (date_sold IS NULL)
-> Index Scan using options_pkey on options co (cost=0.00..8.79 rows=1 width=49)
Index Cond: ((co.fkey_style = iv.chrome_styleid) AND (co.code = io.code))
-> Hash Join (cost=42379.30..137424.09 rows=16729 width=26)
Hash Cond: ((v.lot_id = o.lot_id) AND ((v.vin)::text = (o.vin)::text))
-> Seq Scan on vehicles v (cost=0.00..4547.33 rows=65233 width=24)
-> Hash (cost=20223.32..20223.32 rows=931332 width=44)
-> Seq Scan on options o (cost=0.00..20223.32 rows=931332 width=44)
(17 rows)
这个查询计划的问题 - 我相信我理解 - 最好由 RhodiumToad
说(他在这方面肯定做得更好,所以我敢打赌他的解释会更好)irc://irc.freenode.net/#postgresql
:
oh, that plan is potentially disastrous the problem with that plan is that it's running a hugely expensive hashjoin for each row the problem is the rows=1 estimate from the other join and the planner thinks it's ok to put a hugely expensive query in the inner path of a nestloop where the outer path is estimated to return only one row. since, obviously, by the planner's estimate the expensive part will only be run once but this has an obvious tendency to really mess up in practice the problem is that the planner believes its own estimates ideally, the planner needs to know the difference between "estimated to return 1 row" and "not possible to return more than 1 row" but it's not at all clear how to incorporate that into the existing code
他接着说:
it can affect any join, but usually joins against subqueries are the most likely
现在,当我阅读此计划时,我首先注意到的是 Nested Loop Anti Join
,它的成本为 169,413
(我会坚持使用上限) .此 Anti-Join 分解为成本为 31,738
的 Nested Loop
的结果,以及成本为 Hash Join
的结果137,424
。现在,137,424
比 31,738
大很多,所以我知道问题出在 Hash Join 上。
然后我继续EXPLAIN ANALYZE
查询之外的哈希连接段。它在 7 秒内执行。我确保在 (lot_id, vin) 和 (co.code, and v.code) 上有索引——有。我分别禁用了 seq_scan
和 hashjoin
并注意到速度增加了不到 2 秒。还不足以解释为什么它在一小时后没有进展。
但是,毕竟我完全错了!是的,它是查询中较慢的部分,但因为 rows="1"
位(我假设它在 Nested Loop Anti Join
上)。这是规划器错误估计行数的错误(缺乏能力)?我应该如何解读这一点以得出与 RhodiumToad
相同的结论?
仅仅是 rows="1"
就应该触发我弄清楚这一点吗?
我确实在所有涉及的表上运行了 VACUUM FULL ANALYZE
,这是 Postgresql 8.4。
最佳答案
要看清此类问题,需要了解哪些地方可能出错。但是要找到查询计划中的问题,请尝试从内到外验证生成的计划,检查行数估计是否合理以及成本估计是否与花费的时间匹配。顺便提一句。这两个成本估算不是下限和上限,第一个是生产第一行输出的估算成本,第二个数字是估算的总成本,请参阅 explain documentation有关详细信息,还有一些 planner documentation可用的。它还有助于了解不同的访问方法是如何工作的。作为起点,维基百科有关于 nested loop 的信息, hash和 merge joins .
在您的示例中,您将从:
-> Seq Scan on options io (cost=0.00..20223.32 rows=23004 width=36)
Filter: (name IS NULL)
运行 EXPLAIN ANALYZE SELECT * FROM options WHERE name IS NULL;
并查看返回的行是否与估计匹配。相差 2 通常不是问题,您要尝试发现数量级的差异。
然后查看 EXPLAIN ANALYZE SELECT * FROM vehicles WHERE date_sold IS NULL;
返回预期的行数。
然后上一层到散列连接:
-> Hash Join (cost=5301.58..29722.32 rows=229 width=40)
Hash Cond: ((io.lot_id = iv.lot_id) AND ((io.vin)::text = (iv.vin)::text))
看看 EXPLAIN ANALYZE SELECT * FROM vehicles AS iv INNER JOIN options io ON (io.lot_id = iv.lot_id) AND ((io.vin)::text = (iv.vin)::text) WHERE iv.date_sold IS NULL AND io.name IS NULL;
结果为 229 行。
再往上一层添加 INNER JOIN options co ON (co.fkey_style = iv.chrome_styleid) AND (co.code = io.code)
并且预计只返回一行。这可能是问题所在,因为如果实际行数从 1 变为 100,则遍历包含嵌套循环的内部循环的总成本估算将减少 100 倍。
规划器所犯的潜在错误可能是它期望加入 co
的两个谓词彼此独立,并增加了它们的选择性。而实际上它们可能高度相关并且选择性更接近 MIN(s1, s2) 而不是 s1*s2。
关于postgresql - 读取 PostgreSQL 查询计划时如何获得 "think better"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2337455/
我循环遍历字符串列表以查看该字符串是否包含在字典的值中,然后尝试从该值中删除该字符串。 目前我是这样做的: Dictionary formValues = new Dictionary(); form
我正在将一些旧的 Java 4 代码更新到 Java 8(这里粘贴的太多了),最初的程序员选择让他们的几乎每个类都扩展这个只有静态方法和常量的巨大类,但我不知道他们的推理。 例如: public cl
在使用 z3 解决整数实数约束时,以下两种编写(等效)约束的方法中哪一种更可取(性能方面)? (断言(=>(和( (and (<= (/1.0 1024.0) value) (< value (/1.
我知道这是一个会引起很多争论的话题,但我想知道人们认为使用对象数据源的各种利弊是什么。我现在正在和另一个程序员做一个项目,他的经验和舒适度都 Root 于经典的 ASP,我不确定哪种方式会 a) 快速
抱歉,这是comp-sci 101的问题。我只是不确定是否缺少明显的东西。 因此,假设某些用户输入引发了错误,而我想捕获它并返回一些反馈。错误将是一个数字,0-8。0表示“无错误”。如果错误为3(假设
我们的 JSF Web 应用程序中有多个具有类似功能的搜索页面: 他们有搜索结果(将这些对象称为 T) 有一个包含搜索条件的对象(将此对象称为 C) 他们能够用名称保存搜索条件(将此对象称为 S) 所
我想创建一系列从基础对象继承或复制实例属性的对象。这使我决定使用哪种模式,我想询问您对哪种方法“更好”的看法。 //APPLY: // --------------------------------
我正在构建我的第一个 android 应用程序,也是我的第一个 Java 应用程序。我似乎无法理解枚举和数组列表之间的区别。我正在构建一个简单的闪存卡应用程序,它将包含带有问题的闪存卡,并将其存储为图
我有来自不同来源的客户和潜在客户,我需要弄清楚客户是否已经注册为潜在客户。 我使用 12 个字段进行匹配: address1_clear address2_clear address_clear co
Python 中最好的文字定界符是什么?为什么?单 ' 还是双 "?最重要的是,为什么? 我是 Python 的初学者,我正在努力坚持使用一个。我知道在 PHP 中,例如 "是首选,因为 PHP 不会
这个问题在这里已经有了答案: how to compare two optional NSArrays in Swift (4 个答案) 关闭 6 年前。 我正试图找到一种更好的方法来测试平等性。我
当您有一个表示为数组的循环缓冲区,并且您需要环绕索引(即,当您达到可能的最高索引并递增它时),是否“更好”: return (++i == buffer.length) ? 0: i; 或者 retu
有没有更好的(即更易读的)方式来写这个? if (isset($input_vars['directive']) && $input_vars['directive'] == 'edit') { 最佳
如果我必须在一个句子中找到 let's say a word,我可以想到两种方法 使用 string.IndexOf 使用正则表达式 哪个在性能或最佳实践方面更好 最佳答案 如果不用正则表达式做某事相
我通常知道两种用 C 语言设计通用链表数据结构的方法。我想知道哪种方法更好。在提问之前,我将简要介绍这两种方法: 一种方法是围绕如下结构构建函数: struct list_element {
我总是假设将 double 除以整数会导致更快的代码,因为编译器会选择更好的微码来计算: double a; double b = a/3.0; double c = a/3; // will com
有时,Border控制或 Rectangle控制将满足我的需求。一个例子是,当我正在实现 ControlTemplate 并且我已经在应用分层技术(即在网格中堆叠控件)时,我不需要将不同的 Radiu
代码 (Java) 片段 ..... ..... if ( response.check() == checkNumber ) { String message = "You ar
投资组合A→基金1 投资组合A→基金2 投资组合A→基金3 如果不使用is/has,我就无法框定我的句子。但是在1和2之间 1)具有: class PortfolioA { List obj;
我只是想知道哪个更好,或者更推荐用于处理表单数据。 // Controller // validation etc $data = array('name'=>$this->input->post('
我是一名优秀的程序员,十分优秀!