Sql 性能显著下降,情况应评估一次

Sql 性能显著下降,情况应评估一次,sql,postgresql,Sql,Postgresql,我有一个问题,添加一个简单的测试条件(应该是 每个查询只计算一次)整个查询中的结果将使用十次 只要能回来。我正在运行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 NU

我有一个问题,添加一个简单的测试条件(应该是 每个查询只计算一次)整个查询中的结果将使用十次 只要能回来。我正在运行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)以及与错误相关联的标记集必须 是所提供的一组标记名的超集(在 准备好的声明)。在尝试了几种方法之后,下面是一种 这会产生最好的结果。其基本思想是首先获取所有 满足$TAGNAMES条件的bug,然后测试每个bug的 $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;
显然,当len($TAGNAMES)出现时,添加测试条件会获得丰厚的回报= 0,否则将导致灾难。这是令人费解的,因为条件 独立于每行,因此只应计算一次。 此外,解释分析(相当长)的结果确实表明 在len($TAGNAMES)=1的情况下使用/不使用的计划是 非常不同,尽管它们应该是相同的

无论如何,我怀疑我偶然发现了PostgreSQL查询的一个怪癖(或bug?) 计划者。有什么办法可以绕过它吗

注意:两项测试的解释分析结果如下:
而且。

阅读计划时,主要区别在于快速计划首先过滤结果,然后将其合并。第二个过滤器和嵌套循环联接

关于这个缓慢的查询,有两件事让我印象深刻

首先,它选择了一个糟糕的计划。当您没有足够的内存来确保另一个计划更好时,可能会发生这种情况。尝试将有效缓存大小设置得更高一点,并将工作内存设置得更高一点

第二个问题是,慢速查询缺少哈希聚合。我建议将DISTINCT改为GROUP BY,看看这是否有帮助。我的猜测是,在慢循环中,它可能是具体化了CTE,然后将查询作为嵌套循环对其运行


然而,除了这些,以及可能在系统中添加更多内存之外,我看不到任何让我印象深刻的即时答案。我希望这是有帮助的,如果您在这里无法获得帮助,PostgreSQL上的-perform列表通常非常善于帮助人们。

您能发布
解释分析的输出吗?(理想情况下)查询的主要部分中的括号似乎不平衡。这可能与AND/OR组合有关。@DanielVérité:我已经修复了不平衡的括号。这只是一个复制/粘贴问题;最初的查询是正确的,因此这不是问题所在。@a_horse_,没有名称:我已经添加了EXPLAIN ANALYZE的结果。查看计划的底部-速度慢的计划已决定循环输入。。。来自标签扫描的错误。我猜这和手术室有关
WHERE (type & $TYPE <> 0) AND (bid IN (SELECT * FROM bugs_from_tags))
                            with    without
len($TAGNAMES) = 0:         4       1500
len($TAGNAMES) = 1:         13000   1600