我有一个问题,即添加一个简单的测试条件(应该是 每个查询只评估一次)导致整个查询占用十次 只要回来。我正在运行PostgreSQL 9.2,并且正在运行的表格 如下:
CREATE TABLE tags (
tid int4 UNIQUE NOT NULL,
name text UNIQUE NOT NULL,
PRIMARY KEY (tid));
CREATE TABLE bugs (
bid int4 UNIQUE NOT NULL,
type int2 NOT NULL,
title text NOT NULL,
PRIMARY KEY (bid));
CREATE TABLE bug_tags (
bid int4 REFERENCES bugs(bid) NOT NULL,
tid int4 REFERENCES tags(tid) NOT NULL,
PRIMARY KEY (bid, tid));
CREATE INDEX bug_tags_bid_idx ON bug_tags (bid);
CREATE INDEX bug_tags_tid_idx ON bug_tags (tid);
查询必须返回按bid排序的前20个匹配错误,其中 匹配条件是bug的类型必须符合提供的 位掩码(变量$ TYPE),以及与bug关联的标记集必须 是一组提供的标记名的超集(在$中用$ TAGNAMES表示) 准备好的声明)。在尝试了几种方法之后,下面是一种方法 这会产生最好的结果。基本的想法是首先获取所有 错误满足$ TAGNAMES条件,然后测试每一个 $ TYPE条件。此外,如果$ TAGNAMES为空,那么我们跳过提取 那些错误,而是专注于循环整个表 (因为我们只想要前20行,所以这应该快得多)。 后一种测试导致了令人费解的结果。
WITH tids AS
(SELECT tid
FROM tags
WHERE name = ANY ($TAGNAMES :: text[])),
bugs_from_tags AS
(SELECT DISTINCT t1.bid
FROM bug_tags AS t1
WHERE NOT EXISTS
(SELECT *
FROM tids
WHERE NOT EXISTS
(SELECT *
FROM bug_tags AS t2
WHERE t2.tid = tids.tid AND t2.bid = t1.bid)))
SELECT bid, type, title
FROM bugs
WHERE (type & $TYPE <> 0) AND
(($TAGNAMES :: text[]) = '{}' OR bid IN (SELECT * FROM bugs_from_tags))
ORDER BY bid
LIMIT 20;
没有测试的版本当然是相同的,除了WHERE子句, 这看起来像这样:
WHERE (type & $TYPE <> 0) AND (bid IN (SELECT * FROM bugs_from_tags))
以下是测试数据库的近似ANALYZE结果(随机 数据)由bug_tags中的1,000,000个错误,2,000个标记和200,000行组成。 “with”和“without”列指的是带/不带查询的版本 对空的测试。数字以毫秒为单位。
with without
len($TAGNAMES) = 0: 4 1500
len($TAGNAMES) = 1: 13000 1600
显然,当len($ TAGNAMES)=时,添加测试条件会得到很好的回报
0,否则会导致灾难。这令人费解,因为条件
独立于每一行,因此只应评估一次。
此外,EXPLAIN ANALYZE(很长)的结果确实显示出来
当len($ TAGNAMES)= 1时,有或没有使用的计划是
非常不同,虽然它们应该完全相同!
无论如何,我怀疑我偶然发现了PostgreSQL查询的怪癖(或错误?) 规划师。关于如何绕过它的任何想法?
答案 0 :(得分:0)
阅读计划,主要区别在于快速首先过滤结果然后加入它们。第二个过滤器和嵌套循环连接。
有关缓慢查询的两件事让我感到震惊。
首先是它选择了一个糟糕的计划。当您没有足够的内存以确保其他计划更好时,就会发生这种情况。尝试将effective_cache_size设置得更高一点,将work_mem设置得更高一些。
第二个问题是慢速查询缺少哈希聚合。我建议将DISTINCT更改为GROUP BY,看看这是否有帮助。我的猜测是,在缓慢的情况下,它可能会实现CTE,然后将查询作为嵌套循环运行。
然而,除了这些以及可能在系统中放入更多内存之外,我没有看到任何让我感到紧张的答案。我希望这有用,如果你不能在这里得到帮助,PostgreSQL上的-perform列表通常非常善于帮助人们。