PostgreSQL中非常慢的词典排序?
我有一个PostgreSQL中非常慢的词典排序?,postgresql,postgresql-8.4,postgresql-performance,Postgresql,Postgresql 8.4,Postgresql Performance,我有一个vote\u pairs视图,如下所示: CREATE VIEW vote_pairs AS SELECT v1.name as name1, v2.name as name2, ... FROM votes AS v1 JOIN votes AS v2 ON v1.topic_id = v2.topic_id; 而且,在投票表中有大约100k行,跨此视图执行查询大约需要3秒钟 但是,当我在名称上添
vote\u pairs
视图,如下所示:
CREATE VIEW vote_pairs AS
SELECT
v1.name as name1,
v2.name as name2,
...
FROM votes AS v1
JOIN votes AS v2
ON v1.topic_id = v2.topic_id;
而且,在投票表中有大约100k行,跨此视图执行查询大约需要3秒钟
但是,当我在名称上添加附加过滤器时:
… ON v1.topic_id = v2.topic_id AND v1.name < v2.name;
发生什么事了?博士后的词典比较慢吗?这是别的吗?如何提高查询速度
投票表:
CREATE TABLE votes (
topic_id INTEGER REFERENCES topics(id),
name VARCHAR(64),
vote VARCHAR(12)
)
CREATE INDEX votes_topic_name ON votes (topic_id, name);
CREATE INDEX votes_name ON votes (name);
EXPLAIN ANALYZE
的输出不带名称过滤器:
db=# CREATE OR REPLACE VIEW vote_pairs AS
db-# SELECT
db-# v1.name as name1,
db-# v2.name as name2
db-# FROM votes AS v1
db-# JOIN votes AS v2
db-# ON v1.topic_id = v2.topic_id;
CREATE VIEW
db=# EXPLAIN ANALYZE SELECT * FROM vote_pairs; QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=3956.38..71868.56 rows=5147800 width=28) (actual time=51.810..1236.673 rows=5082750 loops=1)
Hash Cond: (v1.topic_id = v2.topic_id)
-> Seq Scan on votes v1 (cost=0.00..1882.50 rows=112950 width=18) (actual time=0.019..18.358 rows=112950 loops=1)
-> Hash (cost=1882.50..1882.50 rows=112950 width=18) (actual time=50.671..50.671 rows=112950 loops=1)
-> Seq Scan on votes v2 (cost=0.00..1882.50 rows=112950 width=18) (actual time=0.004..20.306 rows=112950 loops=1)
Total runtime: 1495.963 ms
(6 rows)
使用过滤器:
db=# CREATE OR REPLACE VIEW vote_pairs AS
db-# SELECT
db-# v1.name as name1,
db-# v2.name as name2
db-# FROM votes AS v1
db-# JOIN votes AS v2
db-# ON v1.topic_id = v2.topic_id AND v1.name < v2.name;
CREATE VIEW
db=# EXPLAIN ANALYZE SELECT * FROM vote_pairs;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Hash Join (cost=3956.38..84738.06 rows=1715933 width=28) (actual time=66.688..6900.478 rows=2484900 loops=1)
Hash Cond: (v1.topic_id = v2.topic_id)
Join Filter: ((v1.name)::text < (v2.name)::text)
-> Seq Scan on votes v1 (cost=0.00..1882.50 rows=112950 width=18) (actual time=0.023..24.539 rows=112950 loops=1)
-> Hash (cost=1882.50..1882.50 rows=112950 width=18) (actual time=65.603..65.603 rows=112950 loops=1)
-> Seq Scan on votes v2 (cost=0.00..1882.50 rows=112950 width=18) (actual time=0.004..26.756 rows=112950 loops=1)
Total runtime: 7048.740 ms
(7 rows)
杂项说明:
真空满
和分析投票
已运行
- 8.4.11和9.2.3的行为方式相同
我猜之所以添加了慢度,是因为v1.name
过滤器为跨积联接中的每一行添加了一些固定的操作集
一个更有效的操作是检查v1.name v2.name
,但随后会得到重复的结果,例如(A,B),(B,A)
。然后,我们可以将v1.name
添加回WHERE
子句中,该子句将删除重复项,并希望由于简化的过滤器而减少行数
试试这个:
CREATE OR REPLACE VIEW vote_pairs AS
SELECT
v1.name as name1,
v2.name as name2
FROM votes AS v1
JOIN votes AS v2
ON v1.topic_id = v2.topic_id AND v1.name <> v2.name
WHERE v1.name < v2.name;
创建或替换视图投票对作为
挑选
v1.name作为名称1,
v2.name作为名称2
投票结果为v1
以v2的身份加入投票
在v1.topic_id=v2.topic_id和v1.name v2.name上
其中v1.name
(编辑:似乎整理“C”
是一种方法,但我会留下这个答案,因为这是一个减少行暴露于慢速操作的好方法。)是的,文本比较有时很慢。您可能想试试:
SELECT * FROM vote_pairs WHERE name1 > name2 collate "C";
这应该更快一些,因为它没有考虑特定于语言环境的比较规则。此外,解释分析结果表明共享缓冲区可能设置得太低。能否提供表的架构以及
解释分析的结果?确定,已添加。此外,我在《纽约时报》上撒了一点谎——事实证明,其中一些时间会用到其他查询上。但是这里的比率仍然是1.5秒和7秒,我不禁想,基本表的结构是问题的根本原因。首先,它没有钥匙。其次,没有明确的理由说明为什么在主题id上加入它是有意义的。结果似乎只是名字或选票的笛卡尔乘积?我想知道处理与筛选器连接的方式是否需要更多内存。你能试着提高工作效率吗?我知道这不是一个真正的解决方案,但如果它有帮助,它可能是一个线索,什么是错误的。值得一看好!这确实有点帮助-它将运行时间从~7秒减少到~4秒…但这仍然比没有比较的情况慢得多。哇!这就做到了——添加collate
可以使查询的速度与不带比较的查询的速度相同(近似)。谢谢如果要执行此操作,可能应该在name
列上添加CHECK
约束,将其限制在(几乎-argh,Shift-JIS)编码常见的7位ASCII字符范围内。如果应用程序不能接受,那么C
collation可能也不会接受。谢谢你的建议。不过,在这种情况下,这并不是一个成熟的应用程序……只是一些一次性的数据分析。但我以后会记住这一点。
CREATE OR REPLACE VIEW vote_pairs AS
SELECT
v1.name as name1,
v2.name as name2
FROM votes AS v1
JOIN votes AS v2
ON v1.topic_id = v2.topic_id AND v1.name <> v2.name
WHERE v1.name < v2.name;
SELECT * FROM vote_pairs WHERE name1 > name2 collate "C";