如何在 PostgreSQL 中使用 DISTINCT 加速查询?
How to speed up query with DISTINCT in PostgreSQL?
如你所见,我有非常简单的 SQL 语句:
SELECT DISTINCT("CITY" || ' | ' || "AREA" || ' | ' || "REGION") AS LOCATION
FROM youtube
我在查询中使用的 youtube
table 有大约 2500 万条记录。查询需要很长时间才能完成(约 25 秒)。我正在尝试加快请求速度。
我创建了一个索引,如下所示,但我的更高查询仍然需要相同的时间才能完成。我做错了什么?顺便说一句,在我的情况下使用“分区”更好吗?
CREATE INDEX location_index ON youtube ("CITY", "AREA", "REGION")
EXPLAIN
returns:
Unique (cost=5984116.71..6111107.27 rows=96410 width=32)
-> Sort (cost=5984116.71..6047611.99 rows=25398112 width=32)
Sort Key: ((((("CITY" || ' | '::text) || "AREA") || ' | '::text) || "REGION"))
-> Seq Scan on youtube (cost=0.00..1037365.24 rows=25398112 width=32)
@george-joseph QUERY PLAN
你的脚本:
既然你在列上有了索引,
如果您执行以下操作,查询计划会是什么样子
SELECT x.city || ' | ' || x.area || ' | ' || x.region
FROM (SELECT DISTINCT city, area, region
FROM youtube) x
索引和分区都帮不了你。
由于 city
、area
和 region
(可能)密切相关,结果行数将比 PostgreSQL 估计的少得多,因为它假定列是独立的来自彼此。
因此您应该在这些列上创建扩展统计信息,这是 PostgreSQL v10 中引入的新功能:
CREATE STATISTICS youtube_stats (ndistinct)
ON "CITY", "AREA", "REGION" FROM youtube;
ANALYZE youtube;
现在 PostgreSQL 可以更好地了解有多少个不同的组。
然后为查询提供大量内存,以便它可以将所有这些组的哈希值放入内存中。然后它可以使用哈希聚合而不是对行进行排序:
SET work_mem = '1GB';
您可能不需要那么多内存;尝试找到更合理的限制。
然后尝试从 George Joseph 的回答中查询:
SELECT x."CITY" || ' | ' || x."AREA" || ' | ' || x."REGION" AS location
FROM (SELECT DISTINCT "CITY", "AREA", "REGION"
FROM youtube) AS x;
索引应该可以提供帮助。尝试将查询写为:
SELECT DISTINCT ON (city, area, region) "CITY" || ' | ' || "AREA" || ' | ' || "REGION") AS LOCATION
FROM youtube
ORDER BY city, area, region;
这可以利用 (city, area, region)
上的索引。
如你所见,我有非常简单的 SQL 语句:
SELECT DISTINCT("CITY" || ' | ' || "AREA" || ' | ' || "REGION") AS LOCATION
FROM youtube
我在查询中使用的 youtube
table 有大约 2500 万条记录。查询需要很长时间才能完成(约 25 秒)。我正在尝试加快请求速度。
我创建了一个索引,如下所示,但我的更高查询仍然需要相同的时间才能完成。我做错了什么?顺便说一句,在我的情况下使用“分区”更好吗?
CREATE INDEX location_index ON youtube ("CITY", "AREA", "REGION")
EXPLAIN
returns:
Unique (cost=5984116.71..6111107.27 rows=96410 width=32)
-> Sort (cost=5984116.71..6047611.99 rows=25398112 width=32)
Sort Key: ((((("CITY" || ' | '::text) || "AREA") || ' | '::text) || "REGION"))
-> Seq Scan on youtube (cost=0.00..1037365.24 rows=25398112 width=32)
@george-joseph QUERY PLAN
你的脚本:
既然你在列上有了索引, 如果您执行以下操作,查询计划会是什么样子
SELECT x.city || ' | ' || x.area || ' | ' || x.region
FROM (SELECT DISTINCT city, area, region
FROM youtube) x
索引和分区都帮不了你。
由于 city
、area
和 region
(可能)密切相关,结果行数将比 PostgreSQL 估计的少得多,因为它假定列是独立的来自彼此。
因此您应该在这些列上创建扩展统计信息,这是 PostgreSQL v10 中引入的新功能:
CREATE STATISTICS youtube_stats (ndistinct)
ON "CITY", "AREA", "REGION" FROM youtube;
ANALYZE youtube;
现在 PostgreSQL 可以更好地了解有多少个不同的组。
然后为查询提供大量内存,以便它可以将所有这些组的哈希值放入内存中。然后它可以使用哈希聚合而不是对行进行排序:
SET work_mem = '1GB';
您可能不需要那么多内存;尝试找到更合理的限制。
然后尝试从 George Joseph 的回答中查询:
SELECT x."CITY" || ' | ' || x."AREA" || ' | ' || x."REGION" AS location
FROM (SELECT DISTINCT "CITY", "AREA", "REGION"
FROM youtube) AS x;
索引应该可以提供帮助。尝试将查询写为:
SELECT DISTINCT ON (city, area, region) "CITY" || ' | ' || "AREA" || ' | ' || "REGION") AS LOCATION
FROM youtube
ORDER BY city, area, region;
这可以利用 (city, area, region)
上的索引。