mysql - 优化工作 MYSQL 语句

标签 mysql sql

背景

我有一个“用户”表、一个“内容”表和一个“content_likes”表。当用户“喜欢”内容项时,就会将关系添加到“content_likes”。简单。

现在我想做的是根据收到的点赞数对内容进行排序。这相对容易,但是,我只想一次检索 10 个项目,然后通过延迟加载检索接下来的 10 个项目,依此类推。如果选择按时间排序,则很容易在选择语句中进行偏移,但是,由于按“喜欢”数量排序,我需要另一列可以偏移。因此,我在结果集中添加了一个“排名”列,然后在下一次调用 10 个项目时,我可以用它来抵消。

这个查询有效并且做了我需要做的事情。但是,我担心性能。任何人都可以建议优化此查询。或者甚至可能是更好的方法。

数据库架构

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

*为简单起见省略了列

查询分割

  • 在 content_likes 关系表中对 content_id 进行分组,并按喜欢 desc 排序
  • 向结果集中添加“排名”列(或行号)并按此排序
  • 加入“内容”表,以便可以忽略带有已删除标记的任何内容
  • 仅返回“排名”(或行号)大于变量的结果
  • 将结果集限制为 10

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

“替代”mysql 查询也可以像我希望的那样工作。内容按用户喜欢的数量排序,我可以通过插入最后一行号来抵消。我在这里尝试做的是限制结果集,这样如果表变得很大,性能就不会受到太大影响。在此示例中,仅返回某个时间跨度内的内容,且限制为 100。然后我可以按行号偏移(延迟加载/分页)

任何帮助或建议总是值得赞赏。我相对来说是 mysql 的新手,所以请友善:)

最佳答案

您可以消除子查询:

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;

这至少会减少需要排序的行数。

关于mysql - 优化工作 MYSQL 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22118410/

相关文章:

php - mysql_real_escape_string 不适合我

mysql - 连接 3 个表以获得单行

php - 如何检查 'YYYY-MM-DD' 格式的日期和 PHP 中 'Unix Time stamp' 格式的日期?

sql - 尝试使用计算列将 "yy/mm/dd hh:mm:ss"(存储为字符)转换为日期时间

java - JDBC 与 Oracle DB - 使用类似条件的参数标记

mysql - 收入和支出计算

PHP MySQL Bulk inserts by BATCH with prepared statements

java - 如何遍历数据库中employeeID列中的所有行并一次检索一个小时工资率?

PHP消息线程系统

MySqlConnection' 在命名空间'MySql.Data.MySqlClient [Visual Basic -VS2008] 中不明确