我有一个带有父子关系表的 PostgreSQL 数据库(9.2)。我有一个查询来查找具有多个父节点的节点。
以下查询有效并返回正确的结果:
SELECT node,parents FROM
(
SELECT nr.child AS node, COUNT(nr.parent) AS parents
FROM node_relation nr
GROUP BY nr.child
) AS count WHERE parents > 1;
结果集:
node | parents
--------+---------
n21174 | 2
n8635 | 2
(2 rows)
表定义为:
Table "public.node_relation"
Column | Type | Modifiers
-------------+-----------------------+---------------
child | character varying(50) | not null
parent | character varying(50) | not null
Indexes:
"node_relation_pkey" PRIMARY KEY, btree (child, parent)
我重写了查询以不使用子选择:
SELECT child AS node, COUNT(parent) AS parents
FROM node_relation
GROUP BY child
HAVING COUNT(parent) > 1;
新查询有效,但我想知道 COUNT 函数被多次调用。
更新:这是查询计划:
QUERY PLAN
-------------------------------------------------------------------------------------------------------------
GroupAggregate (cost=0.00..1658.81 rows=19970 width=16)
Filter: (count(parent) > 1)
-> Index Only Scan using node_relation_pkey on node_relation (cost=0.00..1259.40 rows=19971 width=16)
我更喜欢使用parents
别名,但以下不起作用:
SELECT child AS node, COUNT(parent) AS parents
FROM node_relation
GROUP BY child
HAVING parents > 1;
ERROR: column "parents" does not exist
LINE 1: ...parents FROM node_relation GROUP BY child HAVING parents > ...
^
PostgreSQL 会优化 ? 的多次调用COUNT
?
如果没有,是否有这种查询的替代形式会更有效?
您的第二个查询(您使用
HAVING
子句实现它的那个)可能更快。在您的第一个查询(使用子选择)中,postgres 必须计算整个表的计数值。在您的第二个查询中,一旦计数值超过 1,它就可以开始忽略要计数的行(尽管我不 100% 知道 postgres 是否足够聪明地做到这一点 - 不过我很确定它是)。由于
COUNT()
是一个聚合函数,因此无论返回的行数如何,它都会运行它运行的次数。如果您有一个不是聚合函数的函数,那么在子选择中运行您的组和 where/have 子句可能会更快。我所指的示例:
HAVING
要具体回答您的问题 - 是的,postgres 将跟踪它计算的聚合值并在子句中重新使用它们(而不是重新计算它们) 。我相信它也会在SELECT
子句中重新使用它们(如果出于某种奇怪的原因,您在 中多次运行完全相同的聚合SELECT
)引用Postgres 的优秀文档(我的粗体)
这并没有具体说它重新使用计算值.. 但它暗示它说该
HAVING
子句是在计算聚合之后使用的。