以下 MySQL 查询假设根据帖子的观点 + 评分 + 提交日期按升序对帖子进行排名:
select
cat ,
p.id ,
title ,
p.date ,
shares ,
source ,
cat ,
count(v.post_id) views ,
sum(r.ilike) rating,
r.module ,
r.module_id ,
@Rank := @Rank + 1 AS Rank
from
posts p
JOIN
rates r
on
r.module_id = p.id
AND r.module = 'posts'
JOIN
posts_views v
on
v.post_id = p.id
WHERE
p.date <= UNIX_TIMESTAMP(NOW())
AND p.state = '3'
AND
(
p.cat NOT REGEXP '[[:<:]]15[[:>:]]'
)
GROUP BY
r.module_id
ORDER BY
rating DESC ,
views DESC ,
p.date ASC LIMIT 0, 10
结果有3个问题:
该查询正在生成一个半笛卡尔积。与来自多个匹配的行r
和从多个匹配的行v
,这些行越来越匹配在一起,膨胀的结果rating
和views
。如果我们删除 GROUP BY 和聚合函数,并取回详细信息行,我们可以观察到导致视图计数增加一倍、三倍的“重复”行......
对此的一种解决方法是通过从内联视图中的至少一个子表进行预聚合来避免笛卡尔积。然后我们将派生表连接到posts
表中以获取到外部查询的聚合。
当views
or中没有匹配的行时,我们可能想考虑使用外连接来处理条件rates
,因此我们可以为没有任何视图的帖子返回零计数。
初始化用户定义的变量,作为单独的语句,或在内联视图中。
此外,我们要晋级的所有列引用,既是为了帮助未来的读者(不是强迫他们在表定义一下找出哪些表中的列状cat
或者title
或者source
是从哪里来的),并避免与查询断裂“模糊列”错误,将来当同名列添加到查询中引用的表之一时。
我建议这样的事情:
SELECT p.cat
, p.id
, p.title
, p.date
, p.shares
, p.source
, p.cat
, IFNULL(v.cnt_views,0) AS views
, r.tot_rating AS rating
, r.module
, r.module_id
, @Rank := @Rank + 1 AS Rank
FROM ( SELECT @Rank := 0 ) i
CROSS
JOIN posts p
LEFT
JOIN ( SELECT ra.module_id
, MAX(ra.module) AS module
, SUM(ra.ilike) AS tot_rating
FROM rates ra
WHERE ra.module = 'posts'
GROUP
BY ra.module_id
) r
ON r.module_id = p.id
LEFT
JOIN ( SELECT pv.post_id
, SUM(1) AS cnt_views
FROM posts_views pv
GROUP
BY pv.post_id
) v
ON v.post_id = p.id
WHERE p.date <= UNIX_TIMESTAMP(NOW())
AND p.state = '3'
AND p.cat NOT REGEXP '[[:<:]]15[[:>:]]'
ORDER
BY r.tot_rating DESC
, v.cnt_views DESC
, p.date ASC
LIMIT 0, 10
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句