如何加快对 2.2 亿行的大型表(9 个演出数据)的查询?

Ran*_*dle 40 mysql performance query-performance

问题:

我们有一个社交网站,会员可以在其中相互评价兼容性或匹配度。该user_match_ratings表包含超过 2.2 亿行(9 演出数据或近 20 演出索引)。针对此表的查询通常显示在 slow.log(阈值 > 2 秒)中,并且是系统中记录最频繁的慢查询:

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 1051
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 395357 group by rating;"

Query_time: 4  Lock_time: 0  Rows_sent: 3  Rows_examined: 1294
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 4182969 group by rating;"

Query_time: 3  Lock_time: 0  Rows_sent: 3  Rows_examined: 446
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 630148 group by rating;"

Query_time: 5  Lock_time: 0  Rows_sent: 3  Rows_examined: 3788
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1835698 group by rating;"

Query_time: 17  Lock_time: 0  Rows_sent: 3  Rows_examined: 4311
"select rating, count(*) as tally from user_match_ratings where rated_user_id = 1269322 group by rating;"
Run Code Online (Sandbox Code Playgroud)

MySQL版本:

  • 协议版本:10
  • 版本:5.0.77-log
  • 版本 bdb:Sleepycat 软件:Berkeley DB 4.1.24:(2009 年 1 月 29 日)
  • 版本编译机:x86_64 version_compile_os:redhat-linux-gnu

表信息:

SHOW COLUMNS FROM user_match_ratings;
Run Code Online (Sandbox Code Playgroud)

给出:

???????????????????????????????????????????????????????????????????
? id            ? int(11)    ? NO ? PRI ? NULL   ? auto_increment ?
? rater_user_id ? int(11)    ? NO ? MUL ? NULL   ?                ?
? rated_user_id ? int(11)    ? NO ? MUL ? NULL   ?                ?
? rating        ? varchar(1) ? NO ?     ? NULL   ?                ?
? created_at    ? datetime   ? NO ?     ? NULL   ?                ?
???????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

示例查询:

select * from mutual_match_ratings where id=221673540;
Run Code Online (Sandbox Code Playgroud)

给出:

?????????????????????????????????????????????????????????????????????????????
? id        ? rater_user_id ? rated_user_id ? rating ? created_at           ?
?????????????????????????????????????????????????????????????????????????????
? 221673540 ? 5699713       ? 3890950       ? N      ? 2013-04-09 13:00:38  ?
?????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

索引

该表设置了 3 个索引:

  1. 单索引 rated_user_id
  2. 关于综合指数rater_user_idcreated_at
  3. 关于综合指数rated_user_idrater_user_id
显示来自 user_match_ratings 的索引;

给出:

??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
? Table              ? Non_unique ? Key_name                  ? Seq_in_index ? Column_name   ? Collation ? Cardinality ? Sub_part ? Packed ? Null                    ? Index_type ? Comment          ?
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
? user_match_ratings ? 0          ? PRIMARY                   ? 1            ? id            ? A         ? 220781193   ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
? user_match_ratings ? 1          ? user_match_ratings_index1 ? 1            ? rater_user_id ? A         ? 11039059    ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
? user_match_ratings ? 1          ? user_match_ratings_index1 ? 2            ? created_at    ? A         ? 220781193   ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
? user_match_ratings ? 1          ? user_match_ratings_index2 ? 1            ? rated_user_id ? A         ? 4014203     ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
? user_match_ratings ? 1          ? user_match_ratings_index2 ? 2            ? rater_user_id ? A         ? 220781193   ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
? user_match_ratings ? 1          ? user_match_ratings_index3 ? 1            ? rated_user_id ? A         ? 2480687     ? NULL     ? NULL   ? BTREE                   ?            ?                  ?
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

即使有索引,这些查询也很慢。

我的问题:

是否将此表/数据分离到服务器上的另一个数据库,该服务器有足够的内存来将此数据存储在内存中,这会加速这些查询吗?无论如何,我们可以改进表/索引的设置以加快这些查询的速度吗?

目前我们有 16GB 的内存;但是,我们正在考虑将现有机器升级到 32GB 或添加一台至少有那么多容量的新机器,也许还有固态驱动器。

ype*_*eᵀᴹ 36

关于这个问题的想法,以随机顺序抛出:

  • 此查询的明显索引是:(rated_user_id, rating)。一个只为百万用户中的一个获取数据并且需要 17 秒的查询做错了:从(rated_user_id, rater_user_id)索引读取然后从表中读取列的(数百到数千)值rating,因为rating在任何索引中都没有。因此,查询必须读取位于许多不同磁盘位置的表中的许多行。

  • 在开始在表中添加大量索引之前,尝试分析整个数据库、整个慢查询集的性能,再次检查数据类型的选择、您使用的引擎和配置设置。

  • 考虑迁移到较新版本的 MySQL、5.1、5.5 甚至 5.6(还有:Percona 和 MariaDB 版本)。由于错误已得到纠正,优化器得到改进,您可以将慢查询的低阈值设置为小于 1 秒,从而带来一些好处(比如 10 毫秒)。这将为您提供关于慢查询的更好信息。

  • 数据类型的选择rating很奇怪。VARCHAR(1)? 为什么不CHAR(1)呢?为什么不TINYINT呢?这将为您节省一些空间,无论是在表中还是在(将)包含该列的索引中。varchar(1) 列需要比 char(1) 多一个字节,如果它们是 utf8,则 (var)char 列将需要 3(或 4)个字节,而不是 1(tinyint)。

  • 如果您使用错误的数据类型,性能影响或存储浪费的百分比是多少? (2认同)