首页 > 数据库 > MySQL > 正文

分析MySQL中索引引引发的CPU负载飙升的问题

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

这篇文章主要介绍了分析MySQL中索引引引发的CPU负载飙升的问题,文中提到了独立索引所带来的巨大CPU负担,以提醒在MySQL中使用索引要注意CPU负载的问题,需要的朋友可以参考下

收到一个mysql服务器负载告警,上去一看,load average都飙到280多了,用top一看,CPU跑到了336%,不过IO和内存的负载并不高,根据经验,应该又是一起索引引起的惨案了。

看下processlist以及slow query情况,发现有一个SQL经常出现,执行计划中的扫描记录数看着还可以,单次执行耗时为0.07s,还不算太大。乍一看,可能不是它引发的,但出现频率实在太高,而且执行计划看起来也不够完美:

 

 
  1. mysql> explain SELECT count(1) FROM a , b WHERE a.id = b.video_id and b.state = 1 AND b.column_id = '81'/G 

  1. *************************** 1. row *************************** 
  2. id: 1 
  3. select_type: SIMPLE 
  4. table: b 
  5. type: index_merge 
  6. possible_keys: columnid_videoid,column_id,state,video_time_stamp,idx_videoid 
  7. key: column_id,state 
  8. key_len: 4,4 
  9. ref: NULL 
  10. rows: 100 
  11. Extra: Using intersect(column_id,state); Using where 
  12. *************************** 2. row *************************** 
  13. id: 1 
  14. select_type: SIMPLE 
  15. table: a 
  16. type: eq_ref 
  17. possible_keys: PRIMARY 
  18. keyPRIMARY 
  19. key_len: 4 
  20. ref: b.video_id 
  21. rows: 1 
  22. Extra: Using where; Using index 

再看下该表的索引情况:

 

 
  1. mysql> show index from b/G 
  1. *************************** 1. row *************************** 
  2. Table: b 
  3. Non_unique: 0 
  4. Key_name: PRIMARY 
  5. Seq_in_index: 1 
  6. Column_name: id 
  7. Collation: A 
  8. Cardinality: 167483 
  9. Sub_part: NULL 
  10. Packed: NULL 
  11. Null
  12. Index_type: BTREE 
  13. Comment: 
  14. Index_comment: 
  15. *************************** 2. row *************************** 
  16. Table: b 
  17. Non_unique: 1 
  18. Key_name: column_id 
  19. Seq_in_index: 1 
  20. Column_name: column_id 
  21. Collation: A 
  22. Cardinality: 8374 
  23. Sub_part: NULL 
  24. Packed: NULL 
  25. Null
  26. Index_type: BTREE 
  27. Comment: 
  28. Index_comment: 
  29. *************************** 3. row *************************** 
  30. Table: b 
  31. Non_unique: 1 
  32. Key_name: state 
  33. Seq_in_index: 2 
  34. Column_name: state 
  35. Collation: A 
  36. Cardinality: 5 
  37. Sub_part: NULL 
  38. Packed: NULL 
  39. Null
  40. Index_type: BTREE 
  41. Comment: 
  42. Index_comment: 


?可以看到执行计划中,使用的是index merge,效率自然没有用联合索引(也有的叫做覆盖索引)来的好了,而且 state 字段的基数(唯一性)太差,索引效果很差。删掉两个独立索引,修改成联合看看效果如何:

 

 
  1. mysql> show index from b; 
 
  1. *************************** 1. row *************************** 
  2. Table: b 
  3. Non_unique: 0 
  4. Key_name: PRIMARY 
  5. Seq_in_index: 1 
  6. Column_name: id 
  7. Collation: A 
  8. Cardinality: 128151 
  9. Sub_part: NULL 
  10. Packed: NULL 
  11. Null: 
  12. Index_type: BTREE 
  13. Comment: 
  14. Index_comment: 
  15. *************************** 2. row *************************** 
  16. Table: b 
  17. Non_unique: 1 
  18. Key_name: idx_columnid_state 
  19. Seq_in_index: 1 
  20. Column_name: column_id 
  21. Collation: A 
  22. Cardinality: 3203 
  23. Sub_part: NULL 
  24. Packed: NULL 
  25. Null: 
  26. Index_type: BTREE 
  27. Comment: 
  28. Index_comment: 
  29. *************************** 3. row *************************** 
  30. Table: b 
  31. Non_unique: 1 
  32. Key_name: idx_columnid_state 
  33. Seq_in_index: 2 
  34. Column_name: state 
  35. Collation: A 
  36. Cardinality: 3463 
  37. Sub_part: NULL 
  38. Packed: NULL 
  39. Null: 
  40. Index_type: BTREE 
  41. Comment: 
  42. Index_comment: 
  43.  
  44. mysql> explain SELECT count(1) FROM a , b WHERE a.id = b.video_id and b.state = 1 AND b.column_id = '81' /G 
  45.  
  46. *************************** 1. row *************************** 
  47. id: 1 
  48. select_type: SIMPLE 
  49. table: b 
  50. type: ref 
  51. possible_keys: columnid_videoid,idx_videoid,idx_columnid_state 
  52. key: columnid_videoid 
  53. key_len: 4 
  54. ref: const 
  55. rows: 199 
  56. Extra: Using where 
  57. *************************** 2. row *************************** 
  58. id: 1 
  59. select_type: SIMPLE 
  60. table: a 
  61. type: eq_ref 
  62. possible_keys: PRIMARY 
  63. key: PRIMARY 
  64. key_len: 4 
  65. ref: b.video_id 
  66. rows: 1 
  67. Extra: Using where; Using index 
 

可以看到执行计划变成了只用到了 idx_columnid_state 索引,而且 ref 类型也变成了 const,SQL执行耗时也从0.07s变成了0.00s,相应的CPU负载也从336%突降到了12%不到。

总结下,从多次历史经验来看,如果CPU负载持续很高,但内存和IO都还好的话,这种情况下,首先想到的一定是索引问题,十有八九错不了。

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