17

在 PostgreSQL 中是否有更快的方法来本质上在几行上执行 if ?

说我有一张桌子

ticket | row | archived
1      | 1   | true
1      | 2   | true
1      | 3   | true
2      | 1   | false
2      | 2   | true

有什么办法可以在票 = 的列下方做一个 if 语句?因此,其中票 = 1 将是正确的,因为

true && true && true = true

其中ticket = 2 将是错误的,因为

false && true = false

还是我应该坚持

SELECT ( (SELECT COUNT(*) FROM table WHERE ticket = 1)
       = (SELECT COUNT(*) FROM table WHERE ticket = 1 AND archived = true) )
4

3 回答 3

21

聚合函数bool_and()

简单、简短、清晰:

SELECT bool_and(archived)
FROM   tbl
WHERE  ticket = 1;

手册

如果所有输入值都为真,则为真,否则为假

子查询表达式EXISTS

就像@Mike 提供的一样。

快点。但是您必须另外检查是否ticket = 1存在任何行,否则您将得到不存在票证的错误结果:

SELECT EXISTS (SELECT 1 FROM tbl WHERE ticket=1)
       AND NOT
       EXISTS (SELECT 1 FROM tbl WHERE ticket=1 AND archived = FALSE);

指数

两种形式都可以并且将使用如下索引:

CREATE index tbl_ticket_idx ON tbl (ticket);

..这使得两者都快,但EXISTS查询速度更快,因为一旦找到第一个匹配行,这种形式就可以停止扫描。这两个查询之间几乎没有任何区别,每张票只有几行,但每张票有很多行有很大的不同。

要在 pg 9.2 中使用仅索引扫描,您需要一个格式如下的多列索引

CREATE index tbl_ticket_archived_idx ON tbl (ticket, archived);

在大多数情况下和任何版本的 PostgreSQL 中,这个都更好由于数据对齐,在索引中添加 a根本不会使索引增长。几乎没有任何成本的额外好处。booleaninteger

但是,索引列会阻止 HOT(仅堆元组)更新。比如说, anUPDATE只改变了 column archived。如果该列未被任何索引(以任何方式)使用,则该行可以被热更新。否则不能走这条捷径。更多关于热门更新:

这一切都取决于您的实际工作量。

于 2012-10-22T17:07:57.123 回答
5

怎么样:

select not exists (select 1 from table where ticket=1 and not archived)

我认为这可能比比较计数更有利,因为count 可能会或可能不会使用索引,实际上您只需要知道该票是否存在任何行。 FALSE我认为仅仅创建一个部分索引ticket可能会非常快。

SQL小提琴

于 2012-10-22T16:05:29.710 回答
1
select not false = any (
        select archived
        from foo
        where ticket = 1
    )

SQL小提琴

于 2012-10-22T16:12:33.357 回答