我一直在阅读关于“COUNT(*)without where clause”在PostgreSQL中速度极慢的问题。来自MySQL,我不知道我是否能够在没有再使用它的情况下生活。我还读过,即使你添加一个“where”子句,它也必须从结果中扫描每一行,除非结果很少,否则这将很慢。我已经看到有疯狂的黑客使用触发器和额外的表,但我不喜欢它的外观。我的意思是我是这个RDBMS的新手,只是开始使用基本功能,并且已经必须使用变通方法?
我需要做的一个例子是创建一个防洪机制。类似于if "count(id) where ip = 1.2.3.4" > 100, fail instead of insert
。
所以我的问题是:
答案 0 :(得分:3)
我认为“非常慢”是一种夸张的夸张:)在你的例子中,结果中最多有100行,计算它们的速度非常快。在这种情况下,我很确定你不需要任何黑客或解决方法。
据我了解,“COUNT(*)
没有WHERE
子句在Postgres中较慢”指的是MySQL的MyISAM表存储表头中的总行数,因此执行{{1}是一个O(1)操作 - 只读取标题中的值,就是这样。在Postgres中,由于MVCC和事务,这是无法完成的,它必须扫描每一行以确定它是否在当前事务中可见。
但是,如果在查询中使用SELECT COUNT(*) FROM my_table
子句,则MySQL不再能够从头部读取行数,实际上必须对行进行计数。在这种情况下,我认为与Postgres的性能没有太大差异。
答案 1 :(得分:2)
这主要是在PostgreSQL 9.2中使用仅索引扫描进行整理。你应该没事,只要确保你的autovacuum设置为经常运行。
即使在以前的版本中,我会说“非常慢”可能超过顶部,除非你有大表或非常慢的顺序I / O.它确实需要一个seqscan,所以它并不便宜,但像同步扫描这样的东西有很多帮助。
COUNT(id)
是更好的风格,所以你通常应该更喜欢使用它。我没有详细研究性能影响;我认为 Pg无论如何都只会使用主键,但需要进行更多挖掘而不是我有时间进行验证。
您提议的使用容易出现竞争条件,使其无法在任何数据库中使用。如果您不介意插入(比方说)120条记录而不是计划的100条记录,这可能无关紧要,但如果您需要它,则必须首先锁定表格,否则许多并发插入都会检查计数是否正常,所有人都看到它,然后全部插入一行。
你会发现,一般来说Pg的数量与MySQL中的MVCC,事务安全的InnoDB存储引擎没有什么不同。
如果您正在使用MyISAM,那么,您可以获得速度以换取更多问题而不是我可以扔掉一根棍子;我更喜欢慢速计数无法回滚,数据调整以避免错误作为无法回滚的解决方法,缺乏崩溃安全性等。
答案 2 :(得分:1)
在这种情况下,您可以limit
计算:
select count(id) > 100
where id = 1.2.3.4
limit 101
无论符合条件的行数(例如100,000),它都将停止在101处计数。如果count(id) > 100
它将返回true,否则为false。
您可以将该测试与insert命令结合使用,这样您就不需要往返服务器:
with c as (
select count(id) > 100 as c
from t
where id = 1.2.3.4
limit 101
)
insert into t (x, y)
select 1, 2
where (select c from c)