[英]How to improve the performance of MYSQL query with large data?
我正在使用具有以下数据的MySQL
表:
users(ID, name, email, create_added) (about 10000 rows)
points(user_id, point) (about 15000 rows)
而我的查询:
SELECT u.*, SUM(p.point) point
FROM users u
LEFT JOIN points p ON p.user_id = u.ID
WHERE u.id > 0
GROUP BY u.id
ORDER BY point DESC
LIMIT 0, 10
我只获得前十名用户的最佳评价,但随后死亡。 如何提高查询性能?
就像@Grim所说的那样,可以使用INNER JOIN
代替LEFT JOIN
。 但是,如果您真正寻求优化,我建议您为表users
提供一个额外的字段,并预先计算point
。 在您当前的数据库设计中,该解决方案将击败任何查询优化。
将LEFT JOIN
INNER JOIN
会INNER JOIN
。 确保points.point
和points.user_id
进行索引。 我假设您可以摆脱WHERE
子句,因为u.id
始终大于0(尽管MySQL可能在查询优化阶段为您执行此操作)。
这实际上并不重要,因为您仅获得10行。 MySQL必须对每个用户的分数进行汇总,然后才能对它们进行排序(“使用文件排序”操作。)最后应用LIMIT。
覆盖索引ON points(user_id,point)
将是最佳性能的最佳选择。 (我只是在猜测,没有任何EXPLAIN
输出或表定义。)
users
的id
列可能是主键,或者至少是唯一索引。 因此,很可能您已经有一个id
为开头的索引,如果是InnoDB,则为主键集群索引。)
我很想测试这样的查询:
SELECT u.*
, s.total_points
FROM ( SELECT p.user_id
, SUM(p.point) AS total_points
FROM points p
WHERE p.user_id > 0
GROUP BY p.user_id
ORDER BY total_points DESC
LIMIT 10
) s
JOIN user u
ON u.id = s.user_id
ORDER BY s.total_points DESC
这确实会产生创建派生表的开销,但是要在点上具有适当的索引,并且必须使用user_id的前导列,并包括point列,MySQL可能可以通过使用索引来优化组,并避免使用“ filesort”操作(对于GROUP BY)。
该结果集上可能会执行“使用文件排序”操作,以获取按total_points排序的行。 然后从中获取前10行。
使用这10行,我们可以联接到用户表以获取相应的行。
但是,此结果略有不同,如果前十位中的user_id
值不在用户表中,则该查询将返回少于10行。 (我希望有一个外键定义,所以不会发生,但是我只是在猜测没有表定义。)
一个EXPLAIN
将显示正在使用由MySQL的访问计划。
有想过分区吗? 我目前正在使用大型数据库并成功改善sql查询。
例如,
PARTITION BY RANGE (`ID`) (
PARTITION p1 VALUES LESS THAN (100) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (200) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (300) ENGINE = InnoDB,
... and so on..
)
它使我们在扫描mysql表时可以获得更好的速度。 即使表中有百万行,Mysql也只会扫描包含用户标识1到99的分区p 1。
看看这个http://dev.mysql.com/doc/refman/5.5/en/partitioning.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.