我有一个包含帖子的表格,按以下方式分类:
所有这些“类别”都存储在下一个表(posts_types)中,并通过下一个表(posts_types_assignment)连接。
COUNTing in PostgreSQL is really slow(我在该表中有超过500k的记录),我需要获得按类型/标签/郎的任意组合分类的帖子数量。
如果我通过触发器解决它,它将会充满许多多级循环,这看起来不太好并且难以维护。
有没有其他解决方案如何有效地获取以任何类型/标签/语言分类的实际帖子数量?
答案 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
是一个缓慢的步骤,因为数据库不知道您想要哪些记录,因此必须为帖子和一段元数据(类型,语言或标签)的每个组合创建临时结果集在它上面。
如果这确实是你的问题,那么正确的计划就像这样。加入pta2
到pt1
,在其上添加索引。加入pta1
到pt2
,然后加入第一个查询的结果,然后加入pta2
。算一算。这意味着我们不会获得巨大的结果集。
如果是这种情况,那么一旦你想让它想出一种新的执行计划,就无法告诉查询优化器。但有一种方法可以强迫它。
p
除了随机错别字等,这可能会有所改善。如果没有,请仔细检查表格上的索引。
答案 1 :(得分:1)
正如Btilly指出的那样,如果他正确猜到了架构,那么表设计就无济于事了 - 例如,乍一看,至少有三个表posts_tag(post_id,tag)
{{1 }} post_lang(post_id,lang)
会更自然,也更有效率。
除此之外(或者除此之外),人们可以想到一个表或物化视图,它总结了所有可能的计数,列post_type(post_id,type)
。当然,完全计算这个非常慢,但是(除了第一次)它可以完全“在后台”,在某些时间间隔(如果数据变化不大,如果你不是) t需要精确计数),或急切地使用触发器。
请参阅示例here