公司线上项目一个库的cpu使用率总是偏高,经同事点拨,发现一处索引使用不当。

首先观察下面的表结构。

CREATE TABLE `live_calc_1b` (
  `vid` varchar(100) NOT NULL,
  ...
  PRIMARY KEY (`vid`)
)

再看下面的这个sql。

select * from live_calc_1b where vid = 14635808219671833713;

看似很普通的使用场景却暗藏隐患,发现了没?

正确的使用方式如下所示

select * from live_calc_1b where vid = '14635808219671833713';

两者看似差别仅在于vid对应的值是否被单引号括起来,但效率上却天差地别,接下来我们通过explain语句分析下两者的效率差距。

mysql> explain select * from live_calc_1b where vid = 14635808219671833713\G 
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: live_calc_1b
         type: ALL
possible_keys: PRIMARY
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 117
        Extra: Using where
1 row in set (0.20 sec)

mysql> explain select * from live_calc_1b where vid = '14635808219671833713'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: live_calc_1b
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 302
          ref: const
         rows: 1
        Extra: NULL
1 row in set (0.20 sec)

查询结果的key字段表示用到的索引,后者用到了主键索引,前者没使用索引。这也意味着前者是通过遍历全表找到结果的。

公司的线上环境数据库中的数据量很大,另外出现问题的地方也是一个update语句,为了方便在本文中使用select演示,但原理是一样的。修正之后,cpu利用率降低了一个数量级。

造成这种现象的原因是where语句查询时,数据类型不匹配造成的。若主键是int类型,而查询时使用字符串,也会引发相同问题。

参考


类型转换对 MySQL 选择索引的影响