一、前言

最近在写sql的时候,会格外注意一些sql的优化,针对复杂的sql,优化器使用的方案并不是最佳方案,所以可能需要我们使用force index这种方式来自己选择索引,加快查询速度。这次记录一下明明表中有这个索引,但mysqlforce index 无效的问题。

二、分析问题

1、问题sql

select uuid as small_uuid, user_id as small_user_id from user_server force index (idx_reg_time)  where 1 and reg_time >=
CONVERT_TZ('2019-07-30 00:00:00','-07:00','-07:00') ;

这里贴出来的sql是简化过的,实际的sql主要是和三个表关联查询,一个千万级,两个百万级,虽然表的数据很唬人,但是通过where条件的筛选,实际查询的数据量是60W左右,预期是1s内完成。但实际上却花了18s

2、执行计划

mysql> explain select uuid as small_uuid, user_id as small_user_id from user_server force index (idx_reg_time)  where 1 and reg_time >= -> CONVERT_TZ('2019-07-30 00:00:00','-07:00','-07:00');
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table       | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | user_server | ALL  | idx_reg_time  | NULL | NULL    | NULL | 14117522 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)

表中的索引没有用到,导致进行了全表扫描,性能低下。问题是咱们已经用了force index,为啥会用不到索引呢?博主百思不得其解。

3、查看表结构

| user_server | CREATE TABLE `user_server` (`user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,`uin` bigint(20) unsigned NOT NULL,`last_login_ip` varchar(32) NOT NULL DEFAULT '',`reg_time` int(11) NOT NULL DEFAULT '0',    //这里是int (11)PRIMARY KEY (`user_id`),KEY `idx_uin_server_id` (`uin`,`server_id`),KEY `idx_server_id` (`server_id`),KEY `idx_uuid` (`uuid`),KEY `idx_uuid_repeat` (`uuid_repeat`),KEY `idx_reg_time` (`reg_time`)
) ENGINE=InnoDB AUTO_INCREMENT=24805032 DEFAULT CHARSET=utf8 |

在查看表结构的时候,博主注意到reg_time这个字段是int类型,而我们的sql在使用where条件的时候字段格式是不对的,是的,犯了索引中的大忌,索引字段和索引条件的类型必须一致才能用到索引

改sql:

select uuid as small_uuid, user_id as small_user_id from user_server force index (idx_reg_time)  where 1 and reg_time >=
unix_timestamp(CONVERT_TZ('2019-07-30 00:00:00','-07:00','-07:00')) ;         (0.6s)

通过unix_timestamp()方法转换日期为时间戳格式,性能突飞猛进,0.6s就完事了。

4、函数计算影响索引使用

后续又发现一个sql如下:


select uuid as small_uuid, user_id as small_user_id from user_server force index (idx_reg_time) where uuid_repeat = 1 and CONVERT_TZ(reg_time,'-07:00','-07:00') >= unix_timestamp('2019-07-30 00:00:00')

同样的味道,同样的配方,索引还是没作用。。这次倒是很快就发现了问题,是字段上面使用函数导致的。把函数计算放到等式的右边即可。

改为:

select uuid as small_uuid, user_id as small_user_id from user_server force index (idx_reg_time) where uuid_repeat = 1 and reg_time,'-07:00','-07:00'>= unix_timestamp(CONVERT_TZ('2019-07-30 00:00:00','-07:00','-07:00'))

三、sql中没有出现排序操作,但是explain出现了using filesort

这部分是因为group by的原因,mysql在使用 group by 的时候,虽然没有使用 order by,如果没有索引,是可能同时出现 using filesortusing temporary 的。因为 group by 就是先排序在分组,如果没有排序的需要,可以加上一个 order by NULL 来避免排序,这样 using filesort 就会去除,能提升一点性能。

mysql官方解释: 如果使用GROUP BY,则输出行将根据列进行排序,GROUP BY就像您具有ORDER BY相同列的列一样。为了避免GROUP BY 产生排序的开销,添加ORDER BY NULL

SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;

依赖于隐式GROUP BY排序(即,在没有ASCDESC指示符的情况下排序)或显式排序 GROUP BY(即,通过对列使用显式 ASCDESC指示符GROUP BY),不推荐使用。要生成给定的排序顺序,请提供一个ORDER BY子句。

官方手册链接: https://dev.mysql.com/doc/refman/5.7/en/select.html

另外,使用order by null性能上提升的并不多,至少在我测试,查询数据量在300W的时候,使用order by null只比不使用快了0.8-1s,提升很有限。不过减少了文件排序,某种意义上也减轻了mysql的压力,减少了磁盘的部分压力,聊胜于无吧。

总结: 记得在刚开始学习索引相关的内容的时候,还经常看到各种不会使用索引的情况,当时还觉得挺好分辨的。只是纸上得来终觉浅啊,自己不碰到就不知道有多坑爹,代价就是几十条sql挨个排查和我那可怜的一个多小时。要细心!

end

明明表中有这个索引,但mysql的force index 无效?相关推荐

  1. 查看Oracle的表中有哪些索引(用user_indexes和user_ind_columns)

    用user_indexes和user_ind_columns系统表查看已经存在的索引 对于系统中已经存在的索引我们可以通过以下的两个系统视图(user_indexes和user_ind_columns ...

  2. mysql force_MySQL force Index 强制索引概述

    以下的文章主要介绍的是MySQL force Index  强制索引,以及其他的强制操作,其优先操作的具体操作步骤如下:我们以MySQL中常用的hint来进行详细的解析,如果你是经常使用Oracle的 ...

  3. SHOW INDEX FROM 表名,查看mysql表中有哪些索引

  4. Mysql 数据库表中有索引为什么还是查询慢?

    问题分析 在进行数据库查询的时候,我们都知道索引可以加快数据查询的效率.但是在实际的业务场景下,经常会遇到即使在表中增加了索引,但是同样还是会出现数据查询慢的问题.这就需要具体分析数据查询慢的具体原因 ...

  5. 【MySQL系统学习专栏】- 数据表操作 - 表定义选项 - 索引

    文章目录 前言 一.索引概述 (一)什么是索引 (二)索引优点 (三)索引缺点 二.索引类型及对应操作 (一)主键索引 (二)普通索引 (三)唯一索引 (四)全文索引 (五)多列索引(组合.复合.联合 ...

  6. MySQL回表与覆盖索引

    MySQL回表与覆盖索引 1. MySQL存储引擎 2. MySQL索引结构 2.1 B树和B+树定义 2.2 B树和B+树区别 2.3 B+Tree优点 3. MySQL索引回表 4. MySQL覆 ...

  7. mysql 索引类型 ref_什么是索引?Mysql目前主要的几种索引类型

    一.索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的My ...

  8. MySQL创建索引跳过redo_明明我建了索引,为什么sql执行的还是这么慢?

    原标题:明明我建了索引,为什么sql执行的还是这么慢? 很多同学经常遇到这样一个问题,就是为了避免sql 执行缓慢,提前将各种可能用到的字段都添加上索引,查询的时候尽可能的使用这些字段,避免全表扫描. ...

  9. mysql 回表查询优化_MySQL中的回表查询与索引覆盖:一次百万级别分页查询使用Limit 从90秒到0.6毫秒的优化...

    这里写目录标题 事故现场 解决方案 提到的"回表查询" InnoDB的索引 什么是回表查询 怎么优化回表查询 事故现场 数据库使用的MySQL,有一个日志表,需要进行分页查询,于是 ...

最新文章

  1. c语言 listview,C语言 SDK编程之通用控件的使用--ListView
  2. 利用二叉树的思想来实现分配和释放内存方法
  3. WebServices 基础知识
  4. 七彩影视双端新版本源码
  5. 零基础Python学习方法,Python入门必读
  6. FileSystemWatcher触发多次Change事件的解决办法 .
  7. 深入解析AsyncTask
  8. DP4 最小花费爬楼梯
  9. 跟我一起来用C++写Web服务器吧
  10. 【Java_基础】java中static与final关键字的区别
  11. 采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统
  12. [技术讨论][DDS] AD9833原理介绍及chiliDDS驱动分享(上)
  13. BCB中利用剪贴板复制粘贴
  14. 注册gitLab时报错There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.
  15. 华为 M5680t对HGU ONU配置指导
  16. wmf图片linux,WMF 文件扩展名: 它是什么以及如何打开它?
  17. Linux的tar命令
  18. 【输入法】 关于win自带的输入法不能打出中文标点
  19. Android包体积优化上篇- 资源混淆优化
  20. 创意三秦——2020 ACA世界大赛陕西赛区成功启动

热门文章

  1. torch分布式训练学习笔记
  2. pytorch tensorboard
  3. onedrive下载
  4. pybind 编码h264
  5. C++默认参数注意事项
  6. Linux中assert头文件,linux系统下如何使用assert函数
  7. java自学语法_Java自学笔记(一):基础知识
  8. java过滤器命名_java--FilenameFilter文件过滤器
  9. python打包成exe_Python打包文件为exe,PyInstaller应用
  10. Fiddler常用功能介绍