PostgreSQL慢COUNT() - 触发唯一的解决方案?

时间:2011-04-11 14:08:24

标签: postgresql triggers count

我有一个包含帖子的表格,按以下方式分类:

  • 标签
  • 语言

所有这些“类别”都存储在下一个表(posts_types)中,并通过下一个表(posts_types_assignment)连接。

COUNTing in PostgreSQL is really slow(我在该表中有超过500k的记录),我需要获得按类型/标签/郎的任意组合分类的帖子数量。

如果我通过触发器解决它,它将会充满许多多级循环,这看起来不太好并且难以维护。

有没有其他解决方案如何有效地获取以任何类型/标签/语言分类的实际帖子数量?

2 个答案:

答案 0 :(得分:1)

让我直截了当。

你有一张桌子posts。你有一张表posts_types。这两个人在posts_types_assignment上有很多人加入。你有一些像这样的查询很慢:

SELECT count(*)
FROM posts p
  JOIN posts_types_assigment pta1
    ON p.id = pta1.post_id
  JOIN posts_types pt1
    ON pt1.id = pta1.post_type_id
      AND pt1.type = 'language'
      AND pt1.name = 'English'
  JOIN posts_types_assigment pta2
    ON p.id = pta2.post_id
  JOIN posts_types pt2
    ON pt2.id = pta2.post_type_id
      AND pt2.type = 'tag'
      AND pt2.name = 'awesome'

而且你想知道为什么它会很慢。

我的第一个注意事项是,如果你在posts表中而不是在连接中有标识符,那么PostgreSQL将不得不做很少的工作。但这是一个没有实际意义的问题,已做出决定。

我更有用的一点是,我相信PostgreSQL有一个类似于Oracle的查询优化器。在这种情况下,为了限制它必须考虑的可能的查询计划的组合爆炸,它只考虑以某个表开始的计划,然后一次重复加入另一个数据集。但是这里没有这样的查询计划。您可以从pt1开始,获取1条记录,然后转到pta1,获取一堆记录,加入p,结束相同数量的记录,然后加入{{1现在你获得了大量的记录,然后加入pta2,只获得一些记录。加入pt2是一个缓慢的步骤,因为数据库不知道您想要哪些记录,因此必须为帖子和一段元数据(类型,语言或标签)的每个组合创建临时结果集在它上面。

如果这确实是你的问题,那么正确的计划就像这样。加入pta2pt1,在其上添加索引。加入pta1pt2,然后加入第一个查询的结果,然后加入pta2。算一算。这意味着我们不会获得巨大的结果集。

如果是这种情况,那么一旦你想让它想出一种新的执行计划,就无法告诉查询优化器。但有一种方法可以强迫它。

p

除了随机错别字等,这可能会有所改善。如果没有,请仔细检查表格上的索引。

答案 1 :(得分:1)

正如Btilly指出的那样,如果他正确猜到了架构,那么表设计就无济于事了 - 例如,乍一看,至少有三个表posts_tag(post_id,tag) {{1 }} post_lang(post_id,lang)会更自然,也更有效率。

除此之外(或者除此之外),人们可以想到一个表或物化视图,它总结了所有可能的计数,列post_type(post_id,type)。当然,完全计算这个非常慢,但是(除了第一次)它可以完全“在后台”,在某些时间间隔(如果数据变化不大,如果你不是) t需要精确计数),或急切地使用触发器。 请参阅示例here