首页 > 数据库 > MySQL > 正文

MySQL的id关联和索引使用的实际优化案例

2024-07-24 12:46:12
字体:
来源:转载
供稿:网友

昨晚收到客服MM电话,一用户反馈数据库响应非常慢,手机收到load异常报警,登上主机后发现大量sql执行非常慢,有的执行时间超过了10s
优化点一:

SELECT * FROM `sitevipdb`.`game_shares_buy_list` WHERE price>='2.00′ ORDER BY tran_id DESC LIMIT 10;

表结构为:

CREATE TABLE `game_shares_buy_list` (`tran_id` int(10) unsigned NOT NULL AUTO_INCREMENT,`………..'PRIMARY KEY (`tran_id`),KEY `ind_username` (`username`)) ENGINE=InnoDB AUTO_INCREMENT=3144200 DEFAULT CHARSET=utf8;

执行计划:

root@127.0.0.1 : sitevipdb 09:10:22> explain SELECT * FROM `sitevipdb`.`game_shares_buy_list` WHERE price>='2.00′ ORDER BY tran_id DESC LIMIT 10;+—-+————-+———————-+——-+—————+———+———+——+——+————-+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+—-+————-+———————-+——-+—————+———+———+——+——+————-+| 1 | SIMPLE | game_shares_buy_list | index | NULL | PRIMARY | 4 | NULL | 10 | Using where |+—-+————-+———————-+——-+—————+———+———+——+——+————-+1 row in set (0.00 sec)

分析该sql的执行计划,由于tran_id是表的主键,所以查询根据主键降序顺序扫描,这样就可以不用排序,
然后在过滤条件price>2.00的记录,看上去这个执行计划貌似非常好,如果查询扫描到了满足条件的10条记录,就会停止扫描;
但是这里有个问题,如果表中有大量的记录是不符合2.00的,意味查询就需要扫描非常多的记录,才能找到符合条件的10条:

root@127.0.0.1 : sitevipdb 09:17:23> select price,count(*) as cnt from `game_shares_buy_list` group by price order by cnt desc limit 10;+——-+——-+| price | cnt |+——-+——-+| 1.75 | 39101 || 1.68 | 38477 || 1.71 | 34869 || 1.66 | 34849 || 1.72 | 34718 || 1.70 | 33996 || 1.76 | 32527 || 1.69 | 27189 || 1.61 | 25694 || 1.25 | 25450 |

可以看到表中有大量的记录不是2.00的,所以这个时候不能在根据主键顺序扫描,在过滤记录;
那么是否需要在price建立一个索引:

root@127.0.0.1 : sitevipdb 09:09:01> select count(*) from `game_shares_buy_list` where price>'2′;+———-+| count(*) |+———-+| 4087 |+———-+root@127.0.0.1 : sitevipdb 09:17:31> select count(*) from `game_shares_buy_list` ;+———-+| count(*) |+———-+| 1572100 |

从上面price的数据分布可以看出,price的分布相对还是比较集中的,如果在price建立索引,mysql也有可能认为由于需要回表的记录过多,
同时需要额外的排序,而不选择在price上的索引:

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表