2013-08-23 43 views
0

我使用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名用户,但随后死亡。我该如何提高查询的性能?

+1

对于这么小的表索引您参加的列上应该足以使这个查询瞬间。 – piotrm

回答

1

LEFT JOIN换成INNER JOIN会有很大帮助。确保points.pointpoints.user_id已编入索引。我假设你可以摆脱WHERE子句,因为u.id将始终大于0(尽管MySQL在查询优化阶段可能会为你做这件事)。

+0

MySQL只能够使用'points'上的其中一个索引。该查询的最佳索引可能是“ON points(user_id,point)”,这是一个覆盖索引。 – spencer7593

2

像@Grim说的,你可以使用INNER JOIN而不是LEFT JOIN。然而,如果你真的寻求优化,我建议你在表users有一个额外的领域与预计算point。这个解决方案可以胜过当前数据库设计的任何查询优化。

1

这并不重要,你只能得到10行。在对数据进行排序之前,MySQL必须总结每个用户的要点(“使用filesort”操作)。LIMIT最后应用。

覆盖指数ON points(user_id,point)将是最佳性能的最佳选择。 (我真的只是猜测,没有任何EXPLAIN输出或表定义。)

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很可能通过使用索引来优化组,并避免使用“Using filesort”操作(对于GROUP BY)。

在结果集上可能会有一个“使用filesort”操作,以获得按total_points排序的行。然后从中获得前10行。

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

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

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

+0

@DRapp,良好的捕获。感谢您修复错误! – spencer7593

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也将只扫描包含用户标识1到99的分区p 1。

看看这个http://dev.mysql.com/doc/refman/5.5/en/partitioning.html