转自http://blog.itpub.net/22664653/viewspace-1791124/

一 背景
 某业务的数据库定期报 thread_runing 飙高,通定位发现一个慢查询sql导致会话堆积。执行sql 耗时如下

  1. root@db 05:32:05>select count(item_id) from xxxtable where selid = 345705650 and end_time > now();
  2. +----------------+
  3. | count(item_id) |
  4. +----------------+
  5. | 2247052 |
  6. +----------------+
  7. 1 row in set (4.65 sec)

二 分析  
慢查询表结构如下

  1. root@db >show create table xxxtable \G
  2. *************************** 1. row ***************************
  3. Table: uac_shop_item_promotion_0091
  4. Create Table: CREATE TABLE `uac_shop_item_promotion_0091` (
  5. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  6. `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  7. `selid` bigint(20) NOT NULL COMMENT '分表字段',
  8. `end_time` datetime NOT NULL COMMENT '活动结束时间',
  9. `item_id` bigint(20) NOT NULL COMMENT '商品id',
  10. PRIMARY KEY (`id`),
  11. UNIQUE KEY `idx_uq_item` (`item_id`),
  12. KEY `idx_deller_id_end_time` (`selid`,`end_time`),
  13. KEY `idx_deller_id_start_time` (`selid`,`start_time`),
  14. KEY `idx_seller_item_start` (`selid`,`start_time`,`item_id`)
  15. ) ENGINE=InnoDB AUTO_INCREMENT=42132149 DEFAULT CHARSET=gbk COMMENT='索引表'
  16. 1 row in set (0.00 sec)

很明显出现问题的sql由于使用了count(item_id) ,而item_id字段并没有和 selid 和end_time 构成有效索引  故该sql 没有合理的使用索引 。查看其直系计划

  1. root@db >explain select count(item_id) from xxxtable
  2. >where selid = 345705650 and end_time > now() \G
  3. *************************** 1. row ***************************
  4. id: 1
  5. select_type: SIMPLE
  6. table: xxxtable
  7. type: ref
  8. possible_keys: idx_deller_id_end_time,idx_deller_id_start_time,idx_seller_item_start
  9. key: idx_deller_id_end_time
  10. key_len: 8
  11. ref: const
  12. rows: 1726757
  13. Extra: Using where
  14. 1 row in set (0.00 sec)

从key_len=8 和Extra: Using where 可以看出MySQL没有完全利用到idx_deller_id_end_time组合索引而是利用到了 selid字段作为过滤条件回表查询。
count(item_id)的意思是符合where条件的结果集中item_id非空集合的总和。
三 如何优化
根据该sql的业务需求是需要获取到某商家参加活动且活动截止时间大于当前时间的商品总数,可以使用如下sql满足要求:

  1. select count(*) from xxxtable where selid = 345705650 and end_time > now()

执行时间仅为原来的1/4,新的sql发布之后thread_running报警消失,业务校验时间明显缩短。

  1. root@db >select count(*) from xxxtable where selid = 345705650 and end_time > now();
  2. +----------+
  3. | count(*) |
  4. +----------+
  5. | 2247052 |
  6. +----------+
  7. 1 row in set (0.82 sec)
  8. root@db >select count(1) from xxxtable where selid = 345705650 and end_time > now();
  9. +----------+
  10. | count(1) |
  11. +----------+
  12. | 2247052 |
  13. +----------+
  14. 1 row in set (0.79 sec)

优化后的sql的explain 方式如下:

  1. root@db >explain select count(*) from xxxtable where selid = 345705650 and end_time > now() \G
  2. *************************** 1. row ***************************
  3. id: 1
  4. select_type: SIMPLE
  5. table: xxxtable
  6. type: range
  7. possible_keys: idx_deller_id_end_time,idx_deller_id_start_time,idx_seller_item_start
  8. key: idx_deller_id_end_time
  9. key_len: 16
  10. ref: NULL
  11. rows: 1726768
  12. Extra: Using where; Using index
  13. 1 row in set (0.00 sec)

四 小结
 a 这个问题是在没有修改索引的基础中做出的优化,老的sql没有有效的利用当前的索引导致耗时操作
 b 对于不同count类型的sql 总结如下
   count(*)/count(1) 返回结果集的总和包括null和重复的值。
   count(column) 返回结果集中非空 column 的总和,执行查询的过程中会校验字段是否非空。
 c 在业务设计的时候 满足业务逻辑的前提下推荐使用count(*).
 d 从官方文档中摘录 Using where 和 Using index 的区别

  1. Using index
  2. The column information is retrieved from the table using only information in the index tree without having to do an additional seek to read the actual row. This strategy can be used when the query uses only columns that are part of a single index.
  3. If the Extra column also says Using where, it means the index is being used to perform lookups of key values. Without Using where, the optimizer may be reading the index to avoid reading data rows but not using it for lookups. For example, if the index is a covering index for the query, the optimizer may scan it without using it for lookups. For InnoDB tables that have a user-defined clustered index, that index can be used even when Using index is absent from the Extra column. This is the case if type is index and key is PRIMARY.
  4. Using where
  5. A WHERE clause is used to restrict which rows to match against the next table or send to the client. Unless you specifically intend to fetch orexamine all rows from the table, you may have something wrong in your query if the Extra value is not Using where and the table join type is ALLor index. Even if you are using an index for all parts of a WHERE clause, you may see Using where if the column can be NULL.

0316 【案例】MySQL count操作优化案例一则的更多相关文章

  1. mysql的sql优化案例

    前言 mysql的sql优化器比较弱,选择执行计划貌似很随机. 案例 一.表结构说明mysql> show create table table_order\G***************** ...

  2. mysql的性能优化案例

    在一次项目实现中,以前写了个程序,将在txt文件中的电话号码和对应的类型往数据库中插入,小数据量的情况下,用个数组遍历循环的方式,很容易解决,但是当数据量一下 但是,几十万个电话一次性插入,就变得耗时 ...

  3. 《Mysql - Count(*) 的优化》

    一:Count(*) 的实现方式? - 要明确的是,在不同的 MySQL 引擎中,count(*) 有不同的实现方式. - MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) ...

  4. mysql优化案例

    MySQL优化案例 Mysql5.1大表分区效率测试 Mysql5.1大表分区效率测试MySQL | add at 2009-03-27 12:29:31 by PConline | view:60, ...

  5. 记一次mysql多表查询(left jion)优化案例

    一次mysql多表查询(left jion)优化案例 在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时, ...

  6. MySQL参数优化案例

    环境介绍 优化层级与指导思想 优化过程 最小化安装情况下的性能表现 优化innodb_buffer_pool_size 优化innodb_log_files_in_group&innodb_l ...

  7. MySQL数据库索引类型、MySQL索引的优化及MySQL索引案例

    关于MySQL索引的好处,如果正确合理设计并且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的MySQL就是一个人力三轮车.对于没有索引的表,单表查询可能几十万数据就是瓶颈,而通常大型 ...

  8. Python 操作mysql数据库之 SQLAlchemy 案例详解

      前言: 字段声明类型中,最右边的是数据库中对应的字段,我们依然可以使用,其左边的的 SQLAchemy 则是其自身封装的自定义类型. 本篇不会讲太多的理论知识,因为这个实用性更强,所以通篇全部都是 ...

  9. MySQL的索引单表优化案例分析

    建表 建立本次优化案例中所需的数据库及数据表 CREATE DATABASE db0206; USE db0206; CREATE TABLE `db0206`.`article`( `id` INT ...

随机推荐

  1. [BZOJ 1718] Redundant Paths

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1718 [算法] 用Tarjan算法找出所有e-DCC(边-双联通分量),然后将这张图 ...

  2. iOS获取相册/相机图片-------自定义获取图片小控件

    一.功能简介 1.封装了一个按钮,点击按钮,会提示从何处获取图片:如果设备支持相机,可以从相机获取,同时还可以从手机相册获取图片. 2.选择图片后,有一个block回调,根据需求,将获得的图片拿来使用 ...

  3. Oracle Instant Client 安装配置

    一.下载 下载地址:http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html 这是Ora ...

  4. java多线程编程之synchronized

    synchronized是用来解决多线程情况下的线程安全问题的,它可以修饰方法也可以修饰语句块 , 那么什么情况下是线程安全和线程不安全呢 ? 方法内的变量是线程安全的 , 类的实例变量是非线程安全的 ...

  5. 从flink-example分析flink组件(1)WordCount batch实战及源码分析

    上一章<windows下flink示例程序的执行> 简单介绍了一下flink在windows下如何通过flink-webui运行已经打包完成的示例程序(jar),那么我们为什么要使用fli ...

  6. C#之调用存储过程

    C#调用存储过程   以下内容可能有错漏之处,请大家多多指教. C#后台代码如下: //调用存储过程的方法public static void Startupworkflow(string first ...

  7. python--6、re模块

    re模块 用于在正则表达式匹配操作. python中为了避免实现输出'\','\n'字符的转义问题(如正则表达式使用反斜杠" \ "来代表特殊形式或用作转义字符,这里跟Python ...

  8. 实现Brush对象的五种图形

    本实例将使用Graphics类绘制五种图形来分别演示SolidBrush.HatchBrush.TextureBrush.LinearGradientBrush.PathGradientBrush这五 ...

  9. [WIFI插座][阅读记录][SoC][RT5350] 00.目录 RALINK AP SDK 4.1.0.0 USER’s MANUAL

    来源是CSDN,百度网盘下载地址 http://pan.baidu.com/share/link?shareid=3504767505&uk=3426044377   授权声明,略过 免责声明 ...

  10. Assembly之instruction之JUMP

    JMP  Jump unconditionally Syntax   JMP  label Operation PC + 2 × offset −> PC Description The 10- ...