postgresql – 在多列上选择DISTINCT

假设我们有一个包含相同数据类型的四列(a,b,c,d)的表.

是否可以选择列中数据中的所有不同值并将它们作为单个列返回,还是必须创建一个函数来实现此目的?

更新:在 SQLfiddle中测试了所有5个查询,其中包含100K行(以及2个单独的案例,一个具有少量(25个)不同的值,另一个具有许多(大约25K值).

一个非常简单的查询是使用UNION disTINCT.我认为如果四个列中的每个列都有一个单独的索引,那将是最有效的.如果Postgres已经实现了Loose Index Scan优化,那么四个列中的每一列都有一个单独的索引是有效的.所以这个查询效率不高,因为它需要对表进行4次扫描(并且不使用索引):

-- Query 1. (334 ms,368ms) 
SELECT a AS abcd FROM tablename 
UNION                           -- means UNION disTINCT
SELECT b FROM tablename 
UNION 
SELECT c FROM tablename 
UNION 
SELECT d FROM tablename ;

一个是第一个UNION ALL,然后使用disTINCT.这还需要4次表扫描(并且不使用索引).当值很少时效率不差,并且在我的(非广泛的)测试中,更多的值变得最快:

-- Query 2. (87 ms,117 ms)
SELECT disTINCT a AS abcd
FROM
  ( SELECT a FROM tablename 
    UNION ALL 
    SELECT b FROM tablename 
    UNION ALL
    SELECT c FROM tablename 
    UNION ALL
    SELECT d FROM tablename 
  ) AS x ;

其他答案提供了使用数组函数或LAteraL语法的更多选项. Jack的查询(187毫秒,261毫秒)具有合理的性能,但AndriyM的查询似乎更有效(125毫秒,155毫秒).它们都对表进行一次顺序扫描,不使用任何索引.

实际上,Jack的查询结果比上面显示的要好一些(如果我们删除了顺序),可以通过删除4个内部区别并仅留下外部区域来进一步改进.

最后,如果 – 且仅当 – 4列的不同值相对较少,您可以使用上面的松散索引扫描页面中描述的WITH RECURSIVE hack / optimization并使用所有4个索引,结果非常快!测试了相同的100K行和大约25个不同的值,分布在4列(仅在2毫秒内运行!),而25K不同的值则是最慢的368毫秒:

-- Query 3.  (2 ms,368ms)
WITH RECURSIVE 
    da AS (
       SELECT min(a) AS n  FROM observations
       UNION ALL
       SELECT (SELECT min(a) FROM observations
               WHERE  a > s.n)
       FROM   da AS s  WHERE s.n IS NOT NULL  ),db AS (
       SELECT min(b) AS n  FROM observations
       UNION ALL
       SELECT (SELECT min(b) FROM observations
               WHERE  b > s.n)
       FROM   db AS s  WHERE s.n IS NOT NULL  ),dc AS (
       SELECT min(c) AS n  FROM observations
       UNION ALL
       SELECT (SELECT min(c) FROM observations
               WHERE  c > s.n)
       FROM   dc AS s  WHERE s.n IS NOT NULL  ),dd AS (
       SELECT min(d) AS n  FROM observations
       UNION ALL
       SELECT (SELECT min(d) FROM observations
               WHERE  d > s.n)
       FROM   db AS s  WHERE s.n IS NOT NULL  )
SELECT n 
FROM 
( TABLE da  UNION 
  TABLE db  UNION 
  TABLE dc  UNION 
  TABLE dd
) AS x 
WHERE n IS NOT NULL ;

SQLfiddle

总而言之,当不同的值很少时,递归查询是绝对的赢家,而有很多值,我的第二个,杰克(下面的改进版本)和AndriyM的查询是最好的表现者.

延迟添加,第一个查询的变体,尽管有额外的独特操作,但比原始的第一个执行得更好,只比第二个稍差:

-- Query 1b.  (85 ms,149 ms)
SELECT disTINCT a AS n FROM observations 
UNION 
SELECT disTINCT b FROM observations 
UNION 
SELECT disTINCT c FROM observations 
UNION 
SELECT disTINCT d FROM observations ;

和杰克的改进:

-- Query 4b.  (104 ms,128 ms)
select distinct unnest( array_agg(a)||
                        array_agg(b)||
                        array_agg(c)||
                        array_agg(d) )
from t ;

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...