PostgreSQL - 检查反向值行是不是存在的最佳方法

Posted

技术标签:

【中文标题】PostgreSQL - 检查反向值行是不是存在的最佳方法【英文标题】:PostgreSQL - Best way to check the existance of reverse valued rowsPostgreSQL - 检查反向值行是否存在的最佳方法 【发布时间】:2016-12-27 13:18:42 【问题描述】:

我知道我找不到合适的标题。

为了论证,我有这张表:

sender|receiver
   a  |   b
   c  |   d
   d  |   e
   b  |   a
   f  |   q
   q  |   f
   t  |   u

我想计算表中有反向的行数。例如,a|b 行在表格中的反面为 b|a。类似地,f|q 在桌子上与 q|f 有相反的作用。所以,对于这张表,我想要“2”作为答案。

我计算如下:

CREATE TABLE #temptab 
(
  sender     VARCHAR,
  receiver   VARCHAR
);

CREATE TABLE #temptab2 
(
  receiver   VARCHAR,
  sender     VARCHAR
);

INSERT INTO #temptab
(
  sender,
  receiver
)
SELECT DISTINCT sender,
       receiver
FROM table

INSERT INTO #temptab2
(
  receiver,
  sender
)
SELECT DISTINCT receiver,
       sender
FROM table

SELECT COUNT(sender)
FROM (SELECT sender,receiver FROM #temptab INTERSECT SELECT receiver,sender FROM #temptab2

有什么方法可以让我更快地做到这一点?

【问题讨论】:

【参考方案1】:

我会这样做:

select count(*)
from #temptab t
where t.sender < t.receiver and
      exists (select 1
              from #temptab tt
              where tt.sender = t.receiver and tt.receiver = t.sender
             );

这应该在 Postgres 上运行良好。我不确定 Amazon Redshift 上的性能。

另一种方法是使用两个聚合:

select count(*)
from (select least(sender, receiver) as x1, greatest(sender_receiver) as x2,
             count(distinct sender) as cnt
      from #temptab
      group by x1, x2
     ) t
where cnt = 2;

但是,您使用 intersect 的版本可能会更快。

【讨论】:

非常感谢。第一个将我的查询时间从 1 分钟缩短到约 35 秒。【参考方案2】:

最快的方法通常是使用join(特别是如果您在两列上有索引):

select count(*)/2
from sr as t1 join sr as t2 on t2.sender=t1.receiver and t2.receiver=t1.sender;

如果您没有带有 sender=receiver 的行,您也可以使用:

select count(*)
from sr as t1 join sr as t2 on t2.sender=t1.receiver and t2.receiver=t1.sender
where t1.sender < t1.receiver; 

在这两种情况下,将 sr 替换为您的表名。

【讨论】:

以上是关于PostgreSQL - 检查反向值行是不是存在的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

在 PostgreSQL 中检查行是不是存在非常慢

检查 json 类型列 PostgreSQL 中是不是存在字段

如何检查 postgres 用户是不是存在?

检查数据库连接是不是存在

检查对象是不是存在时出现奇怪的错误

PostgreSQL 反向 LIKE