如何用大数据提高MYSQL查询的性能?

时间:2013-08-23 02:55:21

标签: php mysql

我使用的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

我只获得前10名用户的最佳分数,但随后就死了。如何改善查询的性能?

4 个答案:

答案 0 :(得分:2)

与@Grim相同,您可以使用INNER JOIN代替LEFT JOIN。但是,如果您真的想要进行优化,我建议您在表users添加一个预先计算point的额外字段。使用您当前的数据库设计,此解决方案可以胜过任何查询优化。

答案 1 :(得分:1)

LEFT JOIN交换INNER JOIN会有很大帮助。确保将points.pointpoints.user_id编入索引。我假设您可以删除WHERE子句,因为u.id将始终大于0(尽管MySQL可能会在查询优化阶段为您执行此操作)。

答案 2 :(得分:1)

除了你只得到10行并不重要。 MySQL必须在为每个用户排序之前总结点数(“使用filesort”操作。)LIMIT最后应用。

覆盖索引ON points(user_id,point)将是获得最佳效果的最佳选择。 (我真的只是猜测,没有任何EXPLAIN输出或表定义。)

id中的users列可能是主键,或者至少是唯一索引。因此,您可能已经有一个以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)。

可能会对该结果集执行“使用filesort”操作,以获取按total_points排序的行。然后从那里获得前10行。

使用这10行,我们可以加入到用户表中以获取相应的行。

但是......这个结果有一点点差别,如果前10位中user_id的任何值都不在用户表中,则此查询将返回少于10行。 (我希望有一个外键定义,所以这不会发生,但我真的只是猜测没有表定义。)

EXPLAIN将显示MySQL正在使用的访问计划。

答案 3 :(得分:0)

有没有想过分区? 我目前正在使用大型数据库并成功改进了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也只扫描包含用户ID 1到99的分区p 1。

查看此http://dev.mysql.com/doc/refman/5.5/en/partitioning.html