任何人都可以解释为什么PostgreSQL如此运作:
如果我执行此查询
SELECT
*
FROM project_archive_doc as PAD, project_archive_doc as PAD2
WHERE
PAD.id = PAD2.id
这将很简单JOIN
,EXPLAIN
将如下所示:
Hash Join (cost=6.85..13.91 rows=171 width=150)
Hash Cond: (pad.id = pad2.id)
-> Seq Scan on project_archive_doc pad (cost=0.00..4.71 rows=171 width=75)
-> Hash (cost=4.71..4.71 rows=171 width=75)
-> Seq Scan on project_archive_doc pad2 (cost=0.00..4.71 rows=171 width=75)
但如果我将执行此查询:
SELECT *
FROM project_archive_doc as PAD
WHERE
PAD.id = (
SELECT PAD2.id
FROM project_archive_doc as PAD2
WHERE
PAD2.project_id = PAD.project_id
ORDER BY PAD2.created_at
LIMIT 1)
没有联接,EXPLAIN
看起来像:
Seq Scan on project_archive_doc pad (cost=0.00..886.22 rows=1 width=75)"
Filter: (id = (SubPlan 1))
SubPlan 1
-> Limit (cost=5.15..5.15 rows=1 width=8)
-> Sort (cost=5.15..5.15 rows=1 width=8)
Sort Key: pad2.created_at
-> Seq Scan on project_archive_doc pad2 (cost=0.00..5.14 rows=1 width=8)
Filter: (project_id = pad.project_id)
为什么会这样,是否有关于此的文档或文章?
答案 0 :(得分:2)
没有表格定义和数据,这种情况很难具体。通常,PostgreSQL与大多数SQL数据库一样,因为它不会将SQL视为如何执行查询的逐步程序。它更像是对结果的描述,以及您希望数据库如何产生这些结果的提示。
PostgreSQL可以自由地实际执行查询,但它可以最有效地执行查询,只要它产生您想要的结果。
通常它有多种关于如何产生特定结果的选择。它将根据成本估算在它们之间进行选择。
它还可以“理解”编写特定查询的几种不同方式是等效的,并将其转换为另一种更有效的方式。例如,它可以将IN (SELECT ...)
转换为连接,因为它可以证明它们是等效的。
然而,有时对查询的显然微小变化从根本上改变了它的含义,并限制了PostgreSQL可以进行的优化/转换。在子查询中添加LIMIT
或OFFSET
会阻止PostgreSQL从展平它,即通过将其转换为连接将其与外部查询相结合。它还可以防止PostgreSQL在子查询和外部查询之间移动WHERE
子句条目,因为这会改变查询的含义。如果没有LIMIT
或OFFSET
子句,它可以执行这两项操作,因为它们不会更改查询的含义。