以下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个问题:
答案 0 :(得分:0)
该查询正在生成半笛卡尔积。通过使用r
中的多个匹配行和v
中的多个匹配行,这些行将被匹配在一起,从而夸大了rating
和views
的结果。如果我们删除GROUP BY和聚合函数,并返回详细信息行,则可以观察到“重复”行,这些行导致视图计数增加一倍,三倍……
对此的一种解决方法是,通过在嵌入式视图中至少对一个子表进行预聚合来避免使用笛卡尔积。然后,我们将派生表连接到posts
表,以将汇总表添加到外部查询。
当views
或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