我有下表:
CREATE TABLE foo( c1 integer, c2 text )
填写为
INSERT INTO foo
SELECT id, md5(random()::text))
FROM generate_series(1, 1000000) id
我试图探索查询:
EXPLAIN ANALYZE
SELECT c2, COUNT(DISTINCT CASE WHEN c1 < 150 THEN c1 ELSE null END)
FROM foo
GROUP BY c2
只得到了这个:
GroupAggregate (cost=145337.34..165315.50 rows=997816 width=37) (actual time=8684.038..12173.533 rows=999766 loops=1)
-> Sort (cost=145337.34..147837.34 rows=1000000 width=37) (actual time=8683.918..10402.606 rows=1000000 loops=1)
Sort Key: c2
Sort Method: external merge Disk: 48816kB
-> Seq Scan on foo (cost=0.00..18334.00 rows=1000000 width=37) (actual time=0.102..168.323 rows=1000000 loops=1)
规划人员未提供有关如何执行DISTINCT
操作的任何信息。所以,我试着让这个计划更加冗长:
EXPLAIN ANALYZE
SELECT st.c2, COUNT(c1)
FROM (
SELECT c2, CASE WHEN c1 < 150 THEN c1 ELSE null END c1
FROM foo
GROUP BY c2, c1
) st
GROUP BY
st.c2
它给了我一些关于查询的更多信息:
GroupAggregate (cost=145337.34..170339.34 rows=200 width=37) (actual time=8583.758..10793.980 rows=999766 loops=1)
-> Group (cost=145337.34..155337.34 rows=1000000 width=37) (actual time=8583.747..10362.651 rows=1000000 loops=1)
-> Sort (cost=145337.34..147837.34 rows=1000000 width=37) (actual time=8583.738..10112.619 rows=1000000 loops=1)
Sort Key: foo.c2, foo.c1
Sort Method: external merge Disk: 48816kB
-> Seq Scan on foo (cost=0.00..18334.00 rows=1000000 width=37) (actual time=0.084..168.937 rows=1000000 loops=1)
GroupAggregate
的相对成本几乎相同(仅在5 current_setting('seq_page_cost')
中有所不同,实际执行时间也几乎相同。
问题: PostgreSQL
服务器如何执行COUNT (DISTINCT)
操作。它可以使用索引(如果有的话)来提高它的性能吗?从我所看到的,它接近我提供的第二个查询,但不完全是......
答案 0 :(得分:1)
您的查询访问c2到group by和c1来计算低于150的不同值。没有WHERE子句,所以你读了整个表。
有两种情况:
覆盖索引具有已经分类的优点。因此,这是两者中较快的选择。
所以这一切都与COUNT(DISTINCT)无关,你不需要知道DBMS如何在内部处理COUNT(DISTINCT)。
答案 1 :(得分:1)
Postgres可以用count(distinct)
做一个糟糕的工作。通常情况下,这会更好:
SELECT c2, COUNT(c1_new)
FROM (SELECT c2, (CASE WHEN c1 < 150 THEN c1 END) as c1_new
FROM foo
GROUP BY c2, (CASE WHEN c1 < 150 THEN c1 END)
) f
GROUP BY c2;
Postgres将选择更好的算法,因为外部查询中没有count(distinct)
。
您可能对this关于该主题的博文感兴趣。这恰好是Oracle和SQL Server做得更好的一个领域。 (而且,我觉得Hive有同样的问题,但原因有些不同,具有讽刺意味。)