明明表中有这个索引,但mysql的force index 无效?
一、前言
最近在写sql
的时候,会格外注意一些sql
的优化,针对复杂的sql
,优化器使用的方案并不是最佳方案,所以可能需要我们使用force index
这种方式来自己选择索引,加快查询速度。这次记录一下明明表中有这个索引,但mysql
的force 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 filesort
,using 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
排序(即,在没有ASC
或 DESC
指示符的情况下排序)或显式排序 GROUP BY
(即,通过对列使用显式 ASC
或DESC
指示符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 无效?相关推荐
- 查看Oracle的表中有哪些索引(用user_indexes和user_ind_columns)
用user_indexes和user_ind_columns系统表查看已经存在的索引 对于系统中已经存在的索引我们可以通过以下的两个系统视图(user_indexes和user_ind_columns ...
- mysql force_MySQL force Index 强制索引概述
以下的文章主要介绍的是MySQL force Index 强制索引,以及其他的强制操作,其优先操作的具体操作步骤如下:我们以MySQL中常用的hint来进行详细的解析,如果你是经常使用Oracle的 ...
- SHOW INDEX FROM 表名,查看mysql表中有哪些索引
- Mysql 数据库表中有索引为什么还是查询慢?
问题分析 在进行数据库查询的时候,我们都知道索引可以加快数据查询的效率.但是在实际的业务场景下,经常会遇到即使在表中增加了索引,但是同样还是会出现数据查询慢的问题.这就需要具体分析数据查询慢的具体原因 ...
- 【MySQL系统学习专栏】- 数据表操作 - 表定义选项 - 索引
文章目录 前言 一.索引概述 (一)什么是索引 (二)索引优点 (三)索引缺点 二.索引类型及对应操作 (一)主键索引 (二)普通索引 (三)唯一索引 (四)全文索引 (五)多列索引(组合.复合.联合 ...
- MySQL回表与覆盖索引
MySQL回表与覆盖索引 1. MySQL存储引擎 2. MySQL索引结构 2.1 B树和B+树定义 2.2 B树和B+树区别 2.3 B+Tree优点 3. MySQL索引回表 4. MySQL覆 ...
- mysql 索引类型 ref_什么是索引?Mysql目前主要的几种索引类型
一.索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果合理的设计且使用索引的MySQL是一辆兰博基尼的话,那么没有设计和使用索引的My ...
- MySQL创建索引跳过redo_明明我建了索引,为什么sql执行的还是这么慢?
原标题:明明我建了索引,为什么sql执行的还是这么慢? 很多同学经常遇到这样一个问题,就是为了避免sql 执行缓慢,提前将各种可能用到的字段都添加上索引,查询的时候尽可能的使用这些字段,避免全表扫描. ...
- mysql 回表查询优化_MySQL中的回表查询与索引覆盖:一次百万级别分页查询使用Limit 从90秒到0.6毫秒的优化...
这里写目录标题 事故现场 解决方案 提到的"回表查询" InnoDB的索引 什么是回表查询 怎么优化回表查询 事故现场 数据库使用的MySQL,有一个日志表,需要进行分页查询,于是 ...
最新文章
- c语言 listview,C语言 SDK编程之通用控件的使用--ListView
- 利用二叉树的思想来实现分配和释放内存方法
- WebServices 基础知识
- 七彩影视双端新版本源码
- 零基础Python学习方法,Python入门必读
- FileSystemWatcher触发多次Change事件的解决办法 .
- 深入解析AsyncTask
- DP4 最小花费爬楼梯
- 跟我一起来用C++写Web服务器吧
- 【Java_基础】java中static与final关键字的区别
- 采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统
- [技术讨论][DDS] AD9833原理介绍及chiliDDS驱动分享(上)
- BCB中利用剪贴板复制粘贴
- 注册gitLab时报错There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.
- 华为 M5680t对HGU ONU配置指导
- wmf图片linux,WMF 文件扩展名: 它是什么以及如何打开它?
- Linux的tar命令
- 【输入法】 关于win自带的输入法不能打出中文标点
- Android包体积优化上篇- 资源混淆优化
- 创意三秦——2020 ACA世界大赛陕西赛区成功启动