背景
我有一个“用户”表,一个“内容”表和一个“content_likes”表。当用户“喜欢”内容项时,将关系添加到“content_likes”。简单。
现在我要做的是根据收到的喜欢的次数订购内容。这是相对容易的,但是,我只想一次检索10个项目然后使用延迟加载我正在检索接下来的10个项目,依此类推。如果select是按时间排序的,那么在select语句中很容易进行偏移,但是,由于“喜欢”的数量排序,我需要另一列我可以抵消。所以我在结果集中添加了一个“rank”列,然后在下一次调用10个项目时,我可以通过它来抵消。
此查询工作并执行我需要执行的操作。但是,我担心表现。任何人都可以建议优化此查询。甚至可能是一种更好的方法。
DB SCHEMA
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
CREATE TABLE `content` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`owner_id` int(11) NOT NULL,
`added` int(11) NOT NULL,
`deleted` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
CREATE TABLE `content_likes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`added` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
为简单起见,省略了*列
查询细分
MYSQL
SELECT
results.content_id, results.likes, results.rank
FROM
(
SELECT
t1.content_id, t1.likes, @rn:=@rn+1 AS rank
FROM
(
SELECT
cl.content_id,
COUNT(cl.content_id) AS likes
FROM
content_likes cl
GROUP BY
cl.content_id
ORDER BY
likes DESC,
added DESC
) t1, (SELECT @rn:=0) t2
ORDER BY
rank ASC
) results
LEFT JOIN
content c
ON
(c.id = results.content_id)
WHERE
c.deleted <> 1
AND
results.rank > :lastRank
LIMIT
10
MYSQL替代
SELECT
*
FROM
(
SELECT
results.*, @rn:=@rn+1 AS rank
FROM
(
SELECT
c.id, cl.likes
FROM
content c
INNER JOIN
(SELECT content_id, COUNT(content_id) AS likes FROM content_likes GROUP BY content_id ORDER BY likes DESC, added DESC) cl
ON
c.id = cl.content_id
WHERE
c.deleted <> 1
AND
c.added > :timeago
LIMIT
100
) results, (SELECT @rn:=0) t2
) final
WHERE
final.rank > :lastRank
LIMIT
5
“Alternative”mysql查询也可以像我一样工作。内容按用户的喜欢次数排序,我可以通过插入最后一行编号来抵消。我试图在这里做的是限制结果集,以便在表格获得大的性能时不会受到太大影响。在此示例中,仅返回时间范围内的内容,并且将返回限制为100。然后我可以通过行号(延迟加载/分页)
来抵消任何帮助或建议总是受到赞赏。我是mysql的新手,所以要善良:)
答案 0 :(得分:2)
您可以删除子查询:
SELECT results.content_id, results.likes, results.rank
FROM (SELECT cl.content_id, COUNT(cl.content_id) AS likes, @rn:=@rn+1 AS rank
FROMc content_likes cl cross join
(SELECT @rn:=0) t2
GROUP BY cl.content_id
ORDER BY likes DESC, added DESC
) results LEFT JOIN
content c
ON c.id = results.content_id
WHERE c.deleted <> 1 AND
results.rank > :lastRank
LIMIT 10;
但是,我认为这不会对绩效产生明显的影响。您应该做的是存储最后一个数量的喜欢和“添加”值并使用这些来过滤数据。查询需要稍微修正一下,因为在added
子句中没有明确定义order by
:
SELECT results.content_id, results.likes, results.rank, results.added
FROM (SELECT cl.content_id, COUNT(cl.content_id) AS likes, MAX(added) as added, @rn:=@rn+1 AS rank
FROMc content_likes cl cross join
(SELECT @rn := :lastRank) t2
WHERE likes < :likes or
likes = :likes and added < :added
GROUP BY cl.content_id
ORDER BY likes DESC, added DESC
) results LEFT JOIN
content c
ON c.id = results.content_id
WHERE c.deleted <> 1 AND
results.rank > :lastRank
LIMIT 10;
这至少会减少需要排序的行数。