加了索引却不生效可能会有以下几种原因。

1. 索引列是表示式的一部分,或是函数的一部分

如下SQL:

SELECT book_id FROM BOOK WHERE book_id +1 = 5;

或者:

SELECT book_id FROM BOOK WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(gmt_create) <= 10

上述两个 SQL 虽然在列 book_id 和 gmt_create 设置了索引 ,但由于它们是表达式或函数的一部分,导致索引无法生效,最终导致全表扫描。

2. 隐式类型转换

以上两种情况相信不少人都知道索引不能生效,但下面这种隐式类型转换估计会让不少人栽跟头,来看下下面这个例子:
假设有以下表:

CREATE TABLE `tradelog` (`id` int(11) NOT NULL,`tradeid` varchar(32) DEFAULT NULL,`operator` int(11) DEFAULT NULL,`t_modified` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `tradeid` (`tradeid`),KEY `t_modified` (`t_modified`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

执行SQL语句

SELECT * FROM tradelog WHERE tradeid=110717;

交易编号 tradeid 上有索引,但用 EXPLAIN 执行却发现使用了全表扫描,为啥呢,tradeId 的类型是 varchar(32), 而此 SQL 用 tradeid 一个数字类型进行比较,发生了隐形转换,会隐式地将字符串转成整型,如下:

mysql> SELECT * FROM tradelog WHERE CAST(tradid AS signed int) = 110717;

这样也就触发了上文中第一条的规则 ,即:索引列不能是函数的一部分。

3. 隐式编码转化

这种情况非常隐蔽,来看下这个例子

CREATE TABLE `trade_detail` ( `id` int(11) NOT NULL, `tradeid` varchar(32) DEFAULT NULL, `trade_step` int(11) DEFAULT NULL, /*操作步骤*/ `step_info` varchar(32) DEFAULT NULL, /*步骤信息*/ PRIMARY KEY (`id`), KEY `tradeid` (`tradeid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

trade_defail 是交易详情, tradelog 是操作此交易详情的记录,现在要查询 id=2 的交易的所有操作步骤信息,则我们会采用如下方式

SELECT d.* FROM tradelog l, trade_detail d WHERE d.tradeid=l.tradeid AND l.id=2;

由于 tradelog 与 trade_detail 这两个表的字符集不同,且 tradelog 的字符集是 utf8mb4,而 trade_detail 字符集是 utf8, utf8mb4 是 utf8 的超集,所以会自动将 utf8 转成 utf8mb4。即上述语句会发生如下转换:

SELECT d.* FROM tradelog l, trade_detail d WHERE (CONVERT(d.traideid USING utf8mb4)))=l.tradeid AND l.id=2;

自然也就触发了 「索引列不能是函数的一部分」这条规则。怎么解决呢,第一种方案当然是把两个表的字符集改成一样,如果业务量比较大,生产上不方便改的话,还有一种方案是把 utf8mb4 转成 utf8,如下

mysql> SELECT d.* FROM tradelog l , trade_detail d WHERE d.tradeid=CONVERT(l.tradeid USING utf8) AND l.id=2;

这样索引列就生效了。

4. 使用 order by 造成的全表扫描

SELECT * FROM user ORDER BY age DESC

上述语句在 age 上加了索引,但依然造成了全表扫描,这是因为我们使用了 SELECT *,导致回表查询,MySQL 认为回表的代价比全表扫描更大,所以不选择使用索引,如果想使用到 age 的索引,我们可以用覆盖索引来代替:

SELECT age FROM user ORDER BY age DESC

或者加上 limit 的条件(数据比较小)

SELECT * FROM user ORDER BY age DESC limit 10

这样就能利用到索引了。

【MySQL】明明加了索引,为何不生效?相关推荐

  1. mysql关于or的索引问题_SQL优化 MySQL版 - 避免索引失效原则(二)

    作者 : Stanley 罗昊 体验SQL优化中的概率情况 在上一篇文章结尾处,我们在执行查询计划的时候,却发现我明明加了索引,并且也满足了使用索引的条件,但是,给我的优化结果却是失败,从而,得出一个 ...

  2. MySQL中B+树索引,聚簇索引,二级索引,辅助索引,回表,索引生效条件

    对于MySQL,我们经常说调优有一个手段就是加索引,那么为什么加索引能够优化查询,是不是加了索引查询就快了 ? 在MySQL中,存储的单元并不是按照我们理解的一条一条记录,而是按照页来进行存储的,My ...

  3. 明明加了唯一索引,为什么还是产生重复数据?

    前言 前段时间我踩过一个坑:在mysql8的一张innodb引擎的表中,加了唯一索引,但最后发现数据竟然还是重复了. 到底怎么回事呢? 本文通过一次踩坑经历,聊聊唯一索引,一些有意思的知识点. 1.还 ...

  4. mysql 添加索引慢_我就加个索引而已,怎么服务就挂了???

    ❝ 领导让我SQL优化,我直接把服务干挂了... ❞ 前言 MySQL大表加字段或者加索引,是有一定风险的. 大公司一般有DBA,会帮助开发解决这个痛点,可是DBA是怎么做的呢? 小公司没有DBA,作 ...

  5. tp5更新某字段加1_爱可生详解MySQL 8.0:索引特性1-函数索引

    函数索引顾名思义就是加给字段加了函数的索引,这里的函数也可以是表达式.所以也叫表达式索引. MySQL 5.7 推出了虚拟列的功能,MySQL8.0的函数索引内部其实也是依据虚拟列来实现的. 我们考虑 ...

  6. mysql 批量加索引_mysql优化:按期删数据 + 批量insert + 字符串加索引为何很傻

    嗯,犯了一个很低级的错误,最近暴露出来了.html 背景:mysql 1. 内部平台,接口间断性无返回,查询日志注意到失败时,接口耗时达到4000+(正常状态:100+ms)git 2. 增长日志打点 ...

  7. mysql datetime month不走索引_like百分号加前面一定不走索引吗?一不小心就翻车,关于mysql索引那些容易错的点...

    like百分号加前面一定不走索引吗? 正常来讲,我们都知道在mysql的like查询中,百分号加在关键词后面是走索引的,比如 select * like "张三%",而百分号在前面 ...

  8. MySQL锁机制,行锁jingran加在索引上

    锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制,应该都不陌生.?但在这之前我们先来看看并发控制,理清MVCC多版本并发控制和锁的关系,这也是之前我很迷惑的一个点 并发控制技术 在数据库中, ...

  9. mysql or走索引吗_加了索引,mysql查询就一定会用吗?

    小白白跑去鹅厂面试,面试官提出了一个很实际的问题: mysql增加索引,那些情况会失效呢?谈一下实际工作中遇到的情况.我们的小白白又抛出了白氏秘籍:用不用索引,找DBA小姐姐!啊?这是你面试哈,还是D ...

最新文章

  1. wordpress php教程 pdf,wordpress二次开发全能教程.pdf
  2. FFmpeg中拉取rtsp视频流并缩放显示测试代码
  3. 认清Hadoop和Spark的这几点区别,学习时才能事半功倍
  4. Linux kernel 不输出log信息
  5. 【转】PHP foreach 小结
  6. 【jquery模仿net控件】简单的datalist控件更新,及其简单应用
  7. java大公司后端多线程面试题最强分享
  8. 绘制对象iPhone开发基础教程 笔记
  9. Python基础教程:括号()[]{}详解
  10. Linux技巧:多核下绑定硬件/进程到不同CPU
  11. Delphi 的运算符重载(1)
  12. RocketMQ之事务消息
  13. 详解-OTUS(大津法-最大类间方差)原理及C语言代码实现
  14. Android 要收费、闭源恐难于上青天
  15. C语言学习笔记---指针
  16. 不小心合并了icloud通讯录_苹果手机号码被删除如何恢复?找回通讯录的具体步骤...
  17. 关于“undefined reference to”错误
  18. macOS应用程序打开时出现崩溃的情况,怎样处理?
  19. sendTemplateMessage微信小程序消息推送 前段 + 后端(thinkphp3.2)
  20. java php 通讯录,基于ssh/bs/java/asp.net/php/web通讯录管理系统

热门文章

  1. Python新建文件夹
  2. 动态创建form传参
  3. 服务器计时器、Windows 计时器和线程计时器
  4. 网络协议从入门到底层原理(8)HTTPS(成本、通信过程、TLS1.2的连接,配置服务器HTTPS)
  5. 读书笔记_打开量化投资的黑箱11
  6. 人人都是程序员?一边吐槽,一边却偷偷用,低代码工具真香
  7. 别被忽悠了!阿里内部人士:我们正悄悄地拆掉中台,你还在建?
  8. 再复杂的报表,用这3种方式,都能解决!
  9. 数据分析学习笔记—python_word处理及邮件发送
  10. php删除提示信息,php删除一条记录(删除确认提示)