今天,通过使用非常简单的示例,让我们看看在使用的背景下
GROUP/DISTINCT以及LIMIT与它们一起可以带来什么。
现在,如果您在请求中写到“首先连接这些板,然后丢弃所有重复的板,则每个密钥应该只有一个副本” –即使完全不需要连接,也是如此。
有时您很幸运,而且“可以正常使用”,有时会对性能产生不愉快的影响,有时从开发人员的角度来看,它绝对带来了意外的影响。

好吧,也许不是那么壮观,但是...
“甜蜜的情侣”:JOIN + DISTINCT
SELECT DISTINCT
X.*
FROM
X
JOIN
Y
ON Y.fk = X.pk
WHERE
Y.bool_condition;
多么清楚我们想要选择这样的记录X,其中Y具有与满足条件相关的记录。我们通过写一个请求
JOIN-几次获得了一些pk值(实际上是Y中有多少个匹配记录)。如何删除?当然可以DISTINCT!
当每个X记录有几百个链接的Y记录,然后英勇地删除重复项时,这尤其令人“高兴”……该
如何解决?首先,请意识到可以将任务修改为“选择Y具有与满足条件至少相关的Y的记录X” -毕竟,我们不需要Y记录本身。
嵌套的存在
SELECT
*
FROM
X
WHERE
EXISTS(
SELECT
NULL
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
);
某些PostgreSQL版本知道足以在EXISTS中找到第一个可用记录,而较旧的版本则不行。因此,我更喜欢始终指定
LIMIT 1inside EXISTS。
横向联接
SELECT
X.*
FROM
X
, LATERAL (
SELECT
Y.*
FROM
Y
WHERE
fk = X.pk AND
bool_condition
LIMIT 1
) Y
WHERE
Y IS DISTINCT FROM NULL;
如有必要,相同的选项允许同时立即从找到的链接Y记录中返回一些数据。在文章“ PostgreSQL反模式:罕见的条目将飞到JOIN的中间”中讨论了类似的选项。
“为什么要多付钱”:DISTINCT [ON] + LIMIT 1
这种查询转换的另一个优点是,如果只需要记录中的一个/几个,就可以轻松地限制记录的迭代次数,如下所示:
SELECT DISTINCT ON(X.pk)
*
FROM
X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
现在,我们阅读了该请求,并试图了解DBMS打算做什么:
- 我们连接板
- 由X.pk唯一
- 从其余记录中选择一个
也就是说,您得到了什么?唯一记录的“一个记录” -如果您采用非唯一记录的一个,结果会有所改变吗?..“如果没有区别,为什么还要支付更多?”
SELECT
*
FROM
(
SELECT
*
FROM
X
--
LIMIT 1 -- +1 Limit
) X
JOIN
Y
ON Y.fk = X.pk
LIMIT 1;
与主题完全相同
GROUP BY + LIMIT 1。
“我只是问”:隐式GROUP + LIMIT
在执行请求期间,对板或CTE的非空性 进行各种检查时会遇到类似的情况:
...
CASE
WHEN (
SELECT
count(*)
FROM
X
LIMIT 1
) = 0 THEN ...
聚集函数(
count/min/max/sum/...)即使没有明确指示也可以在整个集合上成功执行GROUP BY。只有LIMIT他们对他们不是很友好。
开发人员可能会认为“如果那里有记录,那么我就不再需要LIMIT”。但是不要!因为对于基数是:
- 计算所有记录中的所需内容
- 给你尽可能多的行
根据目标条件,在此处进行以下替换之一是合适的:
(count + LIMIT 1) = 0上NOT EXISTS(LIMIT 1)(count + LIMIT 1) > 0上EXISTS(LIMIT 1)count >= N上(SELECT count(*) FROM (... LIMIT N))
“悬挂多少克”:DISTINCT + LIMIT
SELECT DISTINCT
pk
FROM
X
LIMIT $1
天真的开发人员可以诚实地相信,只要我们发现遇到的第一个不同的值中有1美元,查询就会停止。
将来的某个时候,由于新的“索引跳过扫描”节点(目前正在努力实施该工作,但尚未进行),因此该方法可能并将继续有效。
到目前为止,首先,将检索,唯一记录所有记录,并且仅从记录中返回所请求的记录数。如果我们想要像$ 1 = 4这样的表,并且表中有成千上万的记录,这尤其令人难过。
为了不白费事,我们将使用PostgreSQL Wiki上的递归查询“穷人的DISTINCT”:
