【案例】MySQL count操作优化案例一则

一 背景

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

root@db 05:32:05>select count(item_id) from xxxtable where selid = 345705650 and end_time > now();

+----------------+

| count(item_id) |

+----------------+

| 2247052 |

+----------------+

1 row in set (4.65 sec)

二 分析  
慢查询表结构如下 

root@db >show create table xxxtable \G

*************************** 1. row ***************************

       Table: uac_shop_item_promotion_0091

Create Table: CREATE TABLE `uac_shop_item_promotion_0091` (

  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',

  `gmt_modified` datetime NOT NULL COMMENT '修改时间',

  `selid` bigint(20) NOT NULL COMMENT '分表字段',

  `end_time` datetime NOT NULL COMMENT '活动结束时间',

  `item_id` bigint(20) NOT NULL COMMENT '商品id',

  PRIMARY KEY (`id`),

  UNIQUE KEY `idx_uq_item` (`item_id`),

  KEY `idx_deller_id_end_time` (`selid`,`end_time`),

  KEY `idx_deller_id_start_time` (`selid`,`start_time`),

  KEY `idx_seller_item_start` (`selid`,`start_time`,`item_id`)

) ENGINE=InnoDB AUTO_INCREMENT=42132149 DEFAULT CHARSET=gbk COMMENT='索引表'

1 row in set (0.00 sec)

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

root@db >explain select count(item_id) from xxxtable 

        >where selid = 345705650 and end_time > now() \G

*************************** 1. row ***************************

           id: 1

  select_type: SIMPLE

        table: xxxtable

         type: ref

possible_keys: idx_deller_id_end_time,idx_deller_id_start_time,idx_seller_item_start

          key: idx_deller_id_end_time

      key_len: 8 

          ref: const

         rows: 1726757

        Extra: Using where

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满足要求:

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

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

root@db >select count(*) from xxxtable where selid = 345705650 and end_time > now();

+----------+

| count(*) |

+----------+

| 2247052 |

+----------+

1 row in set (0.82 sec)

root@db >select count(1) from xxxtable where selid = 345705650 and end_time > now();

+----------+

| count(1) |

+----------+

| 2247052 |

+----------+

1 row in set (0.79 sec)

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

root@db >explain select count(*) from xxxtable where selid = 345705650 and end_time > now() \G

*************************** 1. row ***************************

           id: 1

  select_type: SIMPLE

        table: xxxtable

         type: range

possible_keys: idx_deller_id_end_time,idx_deller_id_start_time,idx_seller_item_start

          key: idx_deller_id_end_time

      key_len: 16

          ref: NULL

         rows: 1726768

        Extra: Using where; Using index

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 的区别 

Using index

 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.

 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.

 Using where

 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 or examine 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 ALL or 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.
时间: 2024-11-08 18:13:49

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

MySQL下的RAND()优化案例分析_Mysql

众所周知,在MySQL中,如果直接 ORDER BY RAND() 的话,效率非常差,因为会多次执行.事实上,如果等值查询也是用 RAND() 的话也如此,我们先来看看下面这几个SQL的不同执行计划和执行耗时. 首先,看下建表DDL,这是一个没有显式自增主键的InnoDB表: [yejr@imysql]> show create table t_innodb_random\G *************************** 1. row *************************

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

以下是来自DBA+社群MySQL领域原创专家李海翔分享的MySQL优化案例,关于MySQL V5.6.x/5.7.x SQL查询性能问题.   专家简介   李海翔 网名:那海蓝蓝 DBA+社群MySQL领域原创专家 从事数据库研发.数据库测试与技术管理等工作10余年,对数据库的内核有深入研究,擅长于PostgreSQL和MySQL等开源数据库的内核与架构.现任职于Oracle公司MySQL全球开发团队,从事查询优化技术的研究和MySQL查询优化器的开发工作.著有<数据库查询优化器的艺术>一书

MySQL优化案例系列-mysql分页优化_Mysql

通常,我们会采用ORDER BY LIMIT start, offset 的方式来进行分页查询.例如下面这个SQL: SELECT * FROM `t1` WHERE ftype=1 ORDER BY id DESC LIMIT 100, 10; 或者像下面这个不带任何条件的分页SQL: SELECT * FROM `t1` ORDER BY id DESC LIMIT 100, 10; 一般而言,分页SQL的耗时随着 start 值的增加而急剧增加,我们来看下面这2个不同起始值的分页SQL执行

Mysql性能优化案例研究-覆盖索引和SQL_NO_CACHE_Mysql

场景 产品中有一张图片表pics,数据量将近100万条,有一条相关的查询语句,由于执行频次较高,想针对此语句进行优化 表结构很简单,主要字段: 复制代码 代码如下: user_id 用户ID picname 图片名称 smallimg 小图名称 一个用户会有多条图片记录,现在有一个根据user_id建立的索引:uid,查询语句也很简单:取得某用户的图片集合: 复制代码 代码如下: select picname, smallimg from pics where user_id = xxx; 优化

一个MySQL优化案例的初步思路

今天想起这件同事处理的一个性能优化案例,当时虽然解决了,但是还是留下了几个未解的问题,和大家一起讨论一下. 首先,这个问题是根据反馈sql响应很慢,已经开始影响前端应用的登录了.稍后DBA介入,发现是由于CPU使用率过高导致,为了能够延缓问题和进一步分析,因为数据库中的数据量不大,直接就迁移到了另外一台配置不错的服务器上,但是迁移之后,CPU配置好了很多,问题依旧,同时也在进行问题的诊断和分析. 得到的慢日志如下,发现大多数的响应时间都耗费在了两个SQL上,其实出自同一个存储过程. 1.慢日志

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

昨晚收到客服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

一个优化MySQL查询操作的具体案例分析_Mysql

问题描述 一个用户反映先线一个SQL语句执行时间慢得无法接受.SQL语句看上去很简单(本文描述中修改了表名和字段名): SELECT count(*) FROM a JOIN b ON a.`S` = b.`S` WHERE a.`L` > '2014-03-30 00:55:00' AND a.`L` < '2014-03-30 01:00:00' ; 且查询需要的字段都建了索引,表结构如下: CREATE TABLE `a` ( `L` timestamp NOT NULL DEFAULT

打造月3000返利站优化案例(三)用户体验

前段时间已经浅谈了打造月3000返利站优化案例(二)网站推广.打造月3000返利站优化案例-框架优化,接下来我们就简单来谈谈关于用户体验方面的调整.用户体验讲究从网站印象.网站功能.网站实用性.网站内容等综合因素来改善网站环境,提高用户体验,合理的推广与提高网站用户体验,是提高网站转换率(把流量转化为有效客户的比率)的重要因素.用户体验对于网站的pv.跳出率等都有很大的影响.今天笔者就以返利网站为例和大家一起分享有什么不足的还望指点一二. 互联网有成千上万的各种各样的网站.只要一个好的模式一出来

MSSQL-应用案例-日志表设计优化与实现

title: MSSQL-应用案例-日志表设计优化与实现 author: 风移 摘要 这篇文章从日志表问题引入.日志表的共有特性.日志表的设计需求.设计思路以及设计详细实现的角度,阐述了在SQL Server数据库中如何最优化设计日志表来降低系统资源的占用和提高系统吞吐量. 问题引入 在平时与客户服务与交流过程中,我们不止一次的被客人问及这样的场景:我们现在面临如何设计SQL Server日志表方案,如何最优化设计数据库日志记录表.因为,日志表设计会面对如下问题: 表记录数大:日志表由于记录了