手机微博4040端口SQL优化

现象

某端口常态化延迟,通过使用pt-query-digest发现主要由于一条count(*)语句引发,具体如下:

  1. # 13.5s user time, 40ms system time, 21.58M rss, 156.84M vsz
  2.  
  3. # Current date: Fri Apr 1 17:43:05 2016
  4.  
  5. # Hostname: naga64
  6.  
  7. # Files: /data1/mysql4040/slow.log
  8.  
  9. # Overall: 45.87k total, 53 unique, 1.01 QPS, 9.05x concurrency __________
  10.  
  11. # Time range: 2016-04-01 05:05:02 to 17:43:05
  12.  
  13. # Attribute total min max avg 95% stddev median
  14.  
  15. # ============ ======= ======= ======= ======= ======= ======= =======
  16.  
  17. # Exec time 411622s 1s 238s 9s 29s 13s 6s
  18.  
  19. # Lock time 70s 0 4s 2ms 138us 57ms 76us
  20.  
  21. # Rows sent 12.66M 0 1.31M 289.43 19.46 13.90k 0.99
  22.  
  23. # Rows examine 310.43M 0 5.40M 6.93k 31.59k 65.56k 0.99
  24.  
  25. # Query size 5.89M 17 4.14k 134.67 563.87 150.53 76.28
  26.  
  27. # Profile
  28.  
  29. # Rank Query ID Response time Calls R/Call Apdx V/M Item
  30.  
  31. # ==== ================== ================= ===== ======= ==== ===== =====
  32.  
  33. # 1 0xE74340EE1DEFEC99 317229.0380 77.1% 34627 9.1613 0.11 12.60 SELECT user_rec_?
  34.  
  35. # 2 0xB9959C570826EFA4 72164.9508 17.5% 3746 19.2645 0.15 36.13 SELECT app
  36.  
  37. # 3 0xECEF2B7CA2BE445C 7136.5824 1.7% 3581 1.9929 0.53 2.75 SELECT user_rec_?
  38.  
  39. # 4 0x7B9529D6435F23B3 3465.0381 0.8% 137 25.2922 0.16 33.53 SELECT app
  40.  
  41. # 5 0x270C8D7D3EC37561 2209.2050 0.5% 1087 2.0324 0.51 2.34 SELECT apk
  42.  
  43. # 6 0x6AF45A776EDFF7A9 1921.4956 0.5% 905 2.1232 0.50 2.63 SELECT apk
  44.  
  45. # 7 0x67DC38C9C5F7EEBB 1816.0314 0.4% 108 16.8151 0.08 7.32 SELECT ios_apk
  46.  
  47. # 8 0x5F7E7D2BFA8FB79B 1388.2303 0.3% 518 2.6800 0.49 10.45 SELECT apk cooper
  48.  
  49. # 9 0x79F2C2072394C9BB 1005.4780 0.2% 656 1.5327 0.59 1.64 SELECT user_rec_?b
  50.  
  51. # 10 0x3229403E99601A69 632.3939 0.2% 81 7.8073 0.07 1.07 SELECT ios_app
  52.  
  53. # 11 0x83D4C6B0BB535E12 506.5923 0.1% 15 33.7728 0.10 11.12 SELECT apk
  54.  
  55. # 13 0x2F002402DBB98EE9 226.3586 0.1% 73 3.1008 0.42 4.04 SELECT app
  56.  
  57. # 14 0x992F97D6C4D52DF6 219.2329 0.1% 44 4.9826 0.19 2.00 SHOW STATUS
  58.  
  59. # 16 0x791C5370A1021F19 140.2855 0.0% 30 4.6762 0.25 1.87 SHOW SLAVE STATUS
  60.  
  61. # 18 0x2F27EBCFABB23992 110.6802 0.0% 36 3.0744 0.40 2.47 SELECT app_recommend app
  62.  
  63. # 19 0x980736573219087A 108.8593 0.0% 15 7.2573 0.00 0.45 SELECT ios_app_free ios_app
  64.  
  65. # 20 0x58492BB2C89253D8 71.5322 0.0% 10 7.1532 0.05 0.57 SELECT ios_app_free ios_app
  66.  
  67. # 21 0x0EB86D9E4630253A 61.5251 0.0% 27 2.2787 0.52 0.33 SELECT ios_app_recommend ios_app
  68.  
  69. # 22 0x398799E91C3C2AAD 59.5222 0.0% 12 4.9602 0.33 3.46 SELECT apk cooper
  70.  
  71. # 24 0x53148D850C2E022E 45.0953 0.0% 11 4.0996 0.23 1.04 SELECT ios_app
  72.  
  73. # 25 0x07387FA6467B3DB9 34.6657 0.0% 17 2.0392 0.50 0.39 SELECT app_recommend app
  74.  
  75. # 26 0xBD799CC975081065 31.1719 0.0% 16 1.9482 0.47 0.51 SELECT app
  76.  
  77. # 27 0xB7F06103A7ADA5C0 30.4686 0.0% 13 2.3437 0.42 0.52 SELECT user_rec_?d
  78.  
  79. # 30 0x188747BC3CB9728B 19.8929 0.0% 12 1.6577 0.58 0.22 SELECT app_recommend app
  80.  
  81. # MISC 0xMISC 987.4775 0.2% 92 10.7335 NS 0.0 <29 ITEMS>
  82.  
  83. # Query 1: 0.76 QPS, 6.97x concurrency, ID 0xE74340EE1DEFEC99 at byte 2753434
  84.  
  85. # This item is included in the report because it matches --limit.
  86.  
  87. # Scores: Apdex = 0.11 [1.0], V/M = 12.60
  88.  
  89. # Query_time sparkline: | ^_|
  90.  
  91. # Time range: 2016-04-01 05:05:02 to 17:43:04
  92.  
  93. # Attribute pct total min max avg 95% stddev median
  94.  
  95. # ============ === ======= ======= ======= ======= ======= ======= =======
  96.  
  97. # Count 75 34627
  98.  
  99. # Exec time 77 317229s 1s 174s 9s 23s 11s 7s
  100.  
  101. # Lock time 55 39s 46us 3s 1ms 119us 46ms 73us
  102.  
  103. # Rows sent 0 31.80k 0 1 0.94 0.99 0.23 0.99
  104.  
  105. # Rows examine 0 22.97k 0 5 0.68 0.99 0.55 0.99
  106.  
  107. # Query size 44 2.61M 76 79 79.00 76.28 0.02 76.28
  108.  
  109. # String:
  110.  
  111. # Databases apps
  112.  
  113. # Hosts
  114.  
  115. # Users apps_r
  116.  
  117. # Query_time distribution
  118.  
  119. # 1us
  120.  
  121. # 10us
  122.  
  123. # 100us
  124.  
  125. # 1ms
  126.  
  127. # 10ms
  128.  
  129. # 100ms
  130.  
  131. # 1s ################################################################
  132.  
  133. # 10s+ #######################
  134.  
  135. # Tables
  136.  
  137. # SHOW TABLE STATUS FROM `apps` LIKE 'user_rec_07'\G
  138.  
  139. # SHOW CREATE TABLE `apps`.`user_rec_07`\G
  140.  
  141. # EXPLAIN /*!50100 PARTITIONS*/
  142.  
  143. select count(*) as total from user_rec_07 where type=5 and weiboId=''\G

我们来查看一下这个表的表结构和这条语句的explain结果,看是否可以优化,具体如下:

  1. localhost.apps>show create table user_rec_45;
  2.  
  3. +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  4.  
  5. | Table | Create Table |
  6.  
  7. +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  8.  
  9. | user_rec_45 | CREATE TABLE `user_rec_45` (
  10.  
  11. `id` int(11) NOT NULL AUTO_INCREMENT,
  12.  
  13. `softId` int(11) NOT NULL DEFAULT '',
  14.  
  15. `weiboId` bigint(20) NOT NULL DEFAULT '',
  16.  
  17. `type` tinyint(4) NOT NULL DEFAULT '' COMMENT '0???',
  18.  
  19. `content` varchar(512) NOT NULL DEFAULT '' COMMENT '???????url??????????????',
  20.  
  21. `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  22.  
  23. PRIMARY KEY (`id`),
  24.  
  25. KEY `idx_softId_weiboId` (`softId`,`weiboId`),
  26.  
  27. KEY `idx_weiboId` (`weiboId`),
  28.  
  29. KEY `idx_type` (`type`)
  30.  
  31. ) ENGINE=TokuDB AUTO_INCREMENT=3252283 DEFAULT CHARSET=utf8 ROW_FORMAT=TOKUDB_LZMA |
  32.  
  33. +-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  34.  
  35. 1 row in set (0.00 sec)
  36.  
  37. localhost.apps>explain select count(*) as total from user_rec_07 where type=5 and weiboId=1934676487\G;
  38.  
  39. *************************** 1. row ***************************
  40.  
  41. id: 1
  42.  
  43. select_type: SIMPLE
  44.  
  45. table: user_rec_07
  46.  
  47. type: index_merge
  48.  
  49. possible_keys: idx_weiboId,idx_type
  50.  
  51. key: idx_weiboId,idx_type
  52.  
  53. key_len: 8,1
  54.  
  55. ref: NULL
  56.  
  57. rows: 1
  58.  
  59. Extra: Using intersect(idx_weiboId,idx_type); Using where; Using index
  60.  
  61. 1 row in set (0.01 sec)

可以看到通过type和extra都可以发现其实是用到了index的,但是为这么还会这么慢呢?

ps:一开始看到是tokuDB的引擎,下意识的以为是tk对count()支持不好,后来实践证明,还是index的问题。

推理

这条sql的查询条件还是相当简单的,仅为2个等式,根据个人的习惯,我会先看下这2个等值条件的结果集分别是多大?

首先是weiboID的explain:

  1. localhost.apps>explain select count(*) as total from user_rec_07 where weiboId=1934676487\G;
  2.  
  3. *************************** 1. row ***************************
  4.  
  5. id: 1
  6.  
  7. select_type: SIMPLE
  8.  
  9. table: user_rec_07
  10.  
  11. type: ref
  12.  
  13. possible_keys: idx_weiboId
  14.  
  15. key: idx_weiboId
  16.  
  17. key_len: 8
  18.  
  19. ref: const
  20.  
  21. rows: 18
  22.  
  23. Extra: Using index
  24.  
  25. 1 row in set (0.00 sec)
  26.  
  27. 接下来是typeexplain
  28.  
  29. localhost.apps>explain select count(*) as total from user_rec_07 where type=5\G;
  30.  
  31. *************************** 1. row ***************************
  32.  
  33. id: 1
  34.  
  35. select_type: SIMPLE
  36.  
  37. table: user_rec_07
  38.  
  39. type: ref
  40.  
  41. possible_keys: idx_type
  42.  
  43. key: idx_type
  44.  
  45. key_len: 1
  46.  
  47. ref: const
  48.  
  49. rows: 114834
  50.  
  51. Extra: Using index
  52.  
  53. 1 row in set (0.00 sec)
  54.  
  55. 可以很明显的看到weiboID的区分度还是很好的,而type的就差很多了(需要扫描将近12w rows),但是理论上使用weiboID作为index只需要扫描18 rows左右,按说查询时间应该在5ms之内才对。

我们分别看下3条sql的查询时间:

2个条件:

  1. localhost.apps>select count(*) as total from user_rec_45 where type=5 and weiboId='';
  2.  
  3. +-------+
  4.  
  5. | total |
  6.  
  7. +-------+
  8.  
  9. | 1 |
  10.  
  11. +-------+
  12.  
  13. 1 row in set (0.57 sec)

weiboID作为条件:

  1. localhost.apps>select count(*) as total from user_rec_45 where weiboId=''\G;
  2.  
  3. *************************** 1. row ***************************
  4.  
  5. total: 9
  6.  
  7. 1 row in set (0.00 sec)

type作为条件:

  1. localhost.apps>select count(*) as total from user_rec_45 where type=5\G;
  2.  
  3. *************************** 1. row ***************************
  4.  
  5. total: 103838
  6.  
  7. 1 row in set (0.19 sec)

可以从上面明显的看出来双条件耗时最多570ms,weiboID作为条件0ms,type作为条件190ms

根据以上的结果,我们就可以进行index的优化了。

优化

添加index的思路非常的简单,直接加一个两条件的index即可,具体SQL如下:

localhost.apps>alter table user_rec_45 drop index idx_weiboID,add index idx_weiboID_type(weiboID,type);

我们看下添加前和添加之后的区别:

  1. 添加前:
  2.  
  3. localhost.apps>select count(*) as total from user_rec_45 where type=5 and weiboId='';
  4.  
  5. +-------+
  6.  
  7. | total |
  8.  
  9. +-------+
  10.  
  11. | 1 |
  12.  
  13. +-------+
  14.  
  15. 1 row in set (0.57 sec)
  16.  
  17. 添加后:
  18.  
  19. localhost.apps>select count(*) as total from user_rec_45 where type=5 and weiboId='';
  20.  
  21. +-------+
  22.  
  23. | total |
  24.  
  25. +-------+
  26.  
  27. | 1 |
  28.  
  29. +-------+
  30.  
  31. 1 row in set (0.00 sec)

可以看到效果非常的明显。

从服务器的负载看下:

  1. 修改之前:
  2.  
  3. :: PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
  4.  
  5. :: PM all 96.00 0.00 3.38 0.00 0.00 0.62 0.00 0.00 0.00
  6.  
  7. :: PM 91.00 0.00 5.00 0.00 0.00 4.00 0.00 0.00 0.00
  8.  
  9. :: PM 97.98 0.00 2.02 0.00 0.00 0.00 0.00 0.00 0.00
  10.  
  11. :: PM 98.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00
  12.  
  13. :: PM 96.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 0.00
  14.  
  15. :: PM 95.96 0.00 3.03 0.00 0.00 1.01 0.00 0.00 0.00
  16.  
  17. :: PM 96.00 0.00 4.00 0.00 0.00 0.00 0.00 0.00 0.00
  18.  
  19. :: PM 97.00 0.00 3.00 0.00 0.00 0.00 0.00 0.00 0.00
  20.  
  21. :: PM 97.00 0.00 3.00 0.00 0.00 0.00 0.00 0.00 0.00
  22.  
  23. 修改之后:
  24.  
  25. :: PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
  26.  
  27. :: PM all 24.25 0.00 1.12 3.50 0.00 0.12 0.00 0.00 71.00
  28.  
  29. :: PM 16.16 0.00 2.02 18.18 0.00 1.01 0.00 0.00 62.63
  30.  
  31. :: PM 3.03 0.00 0.00 6.06 0.00 0.00 0.00 0.00 90.91
  32.  
  33. :: PM 90.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 9.00
  34.  
  35. :: PM 84.00 0.00 6.00 2.00 0.00 0.00 0.00 0.00 8.00
  36.  
  37. :: PM 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
  38.  
  39. :: PM 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
  40.  
  41. :: PM 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
  42.  
  43. :: PM 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00

但是为什么会这样呢? 细心的同学应该发现了,之前其实MySQL也使用了2个索引,只不过是使用的index merge,将两个单独的index合并在一起使用了,为什么差距会这么大呢?

分析

我们首先来看下index merge也就是 index intersect(indx1,index2)的定义

  1. index_merge: This join type indicates that the Index Merge optimization is used. In this case, the key column in the output row contains a list of indexes used, and key_len contains a list of the longest key parts for the indexes used.
  2.  
  3. The Index Merge method is used to retrieve rows with several range scans and to merge their results into one. The merge can produce unions, intersections, or unions-of-intersections of its underlying scans. This access method merges index scans from a single table; it does not merge scans across multiple tables.

从上面的解释我们可以看出来,index merge其实就是分别通过对两个独立的index进行过滤之后,将过滤之后的结果聚合在一起,然后在返回结果集。

在我们的这个例子中,由于type字段的过滤性不好,故返回的rows依然很多,所以造成的很多的磁盘read,导致了cpu的负载非常的高,直接就出现了延迟。

ps:其实在这个case中,并不需要加2个条件的index,只需要将type这个index干掉,直接使用weiboID这个index即可,毕竟这个index的过滤的结果集已经很小了。

或者通过关闭index intersect功能也可以。

SET [GLOBAL|SESSION] optimizer_switch="index_merge_intersection=off";

展示一下优化前后的io吞吐:

  1. 优化前
  2.  
  3. ----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
  4.  
  5. usr sys idl wai hiq siq| read writ| recv send| in out | int csw
  6.  
  7. |3842k 3440k| | |
  8.  
  9. | 26M 2593k| 69k 47k| | 31k
  10.  
  11. | 26M 3258k| 79k 47k| | 27k
  12.  
  13. | 24M 12M| 56k 37k| | 21k
  14.  
  15. | 27M 2523k| 56k 20k| | 16k
  16.  
  17. | 25M 2199k| 102k 43k|
  18.  
  19. 优化后
  20.  
  21. ----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
  22.  
  23. usr sys idl wai hiq siq| read writ| recv send| in out | int csw
  24.  
  25. |2935k 3362k| | |
  26.  
  27. |4313k 4330k| 129k 353k| |
  28.  
  29. |4242k 3424k| 138k 392k| | 11k
  30.  
  31. |4441k 3840k| 169k 397k| |
  32.  
  33. |3720k 9161k| 135k 398k| |
  34.  
  35. |4567k 3569k| 139k 368k| |
  36.  
  37. |3972k 4199k| 135k 341k| |

index merge的一次优化的更多相关文章

  1. MySQL 优化之 index merge(索引合并)

    深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where ...

  2. 8.2.1.4 Index Merge Optimization 索引合并优化:

    8.2.1.4 Index Merge Optimization 索引合并优化: 索引合并方法是用于检索记录 使用多个 范围扫描和合并它们的结果集到一起 mysql> show index fr ...

  3. MySQL Index Merge Optimization

    Index Merge用在通过一些range scans得到检索数据行和合并成一个整体.合并可以通过 unions,intersections,或者unions-intersection运用在底层的扫 ...

  4. MySQL index merge

    深入理解 index merge 是使用索引进行优化的重要基础之一. [ index merge]       当where谓词中存在多个条件(或者join)涉及到多个字段,它们之间进行 AND 或者 ...

  5. MySQL 查询优化之 Index Merge

    MySQL 查询优化之 Index Merge Index Merge Intersection 访问算法 Index Merge Union 访问算法 Index Merge Sort-Union ...

  6. MySQL中Index Merge简介

    索引合并优化 官网翻译 MySQL5.7文档 索引合并是为了减少几个范围(type中的range类型:range can be used when a key column is compared t ...

  7. Python, pandas: how to sort dataframe by index// Merge two dataframes by index

    pd.concat([df1, df2], axis=1) df.sort_index(inplace=True) https://stackoverflow.com/questions/404680 ...

  8. 0103MySQL中的B-tree索引 USINGWHERE和USING INDEX同时出现

    转自博客http://www.amogoo.com/article/4 前提1,为了与时俱进,文中数据库环境为MySQL5.6版本2,为了通用,更为了避免造数据的痛苦,文中所涉及表.数据,均来自于My ...

  9. Mysql中的force index和ignore index

    前几天统计一个sql,是一个人提交了多少工单,顺便做了相关sql优化.数据大概2000多w. ) c order by c desc; 为了实验最少受其他因素干扰,将生产库的200多w数据导出来,用测 ...

随机推荐

  1. QCustomplot使用分享(六) 坐标轴和网格线

    一.概述 前边已经写了5篇对QCustomPlot的讲解,看过上述的几篇文章后,基本就能做一些简单的使用了,但是如果想要做到高度的控制图表,那么坐标轴将是很重要的一部分,因为坐标轴就是图表的一个参考系 ...

  2. 关于Form.Close跟Form.Dispose

    我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口.熟悉Winform开发的想必对这些非常熟悉.但是Form类型实现了IDisposable接口,那我 ...

  3. P6 EPPM R16.1安装与配置指南(三)

    P6 EPPM R16.1安装与配置指南(三) 解压:V137390-01.zip 修改 D:\P6_R161\p6suite\database\dbsetup.bat   的行 SET JAR_FI ...

  4. IIS 503日志文件在哪

    概述  503:“服务不可用”错误是一个非自定义的错误,该错误表示服务器当前无法处理该请求. 可能原因:1.管理员可能关闭应用程序池以执行维护.2.当请求到达时应用程序池队列已满.3.应用程序池标识没 ...

  5. JS+JQ手风琴效果

    最新在学习JS写一些实用的小玩意——手风琴 CSS样式: <style type="text/css"> * { margin: 0px; border: 0px; p ...

  6. csharp:百度语音识别

    public string API_id = "8888"; //你的ID public string API_record = null; public string API_r ...

  7. LeetCode131:Palindrome Partitioning

    题目: Given a string s, partition s such that every substring of the partition is a palindrome. Return ...

  8. 初识 easyui datagrid

    首先应该下载好easyui datagrid所用的各种js 和css 这个可以到官网上去下载. 首先要引入datagrid所引入的js和css. <script src="js/jqu ...

  9. [Design Pattern] Substitute Interface

    [Design Pattern] Substitute Interface 目的 将对象的成员建立为替身接口的成员,用来解耦对象之间的循环相依. 情景 假设开发人员接手一个系统,在系统里有订单对象.送 ...

  10. CRM 2013 移动终端 介绍和PAD下载地址

    IPHONE 浏览器界同 Pad 端 APP  (目前不支持中文,大家可以用美国账号下载,谁有分享一下) https://itunes.apple.com/en/app/microsoft-dynam ...