为什么MySQL字符串不加引号索引失效?《死磕MySQL系列 十一》

2023-11-14

群里一个小伙伴在问为什么MySQL字符串不加单引号会导致索引失效,这个问题估计很多人都知道答案。没错,是因为MySQL内部进行了隐式转换。

本期文章就聊聊什么是隐式转换,为什么会发生隐式转换。

系列文章

字符串可以这样加索引,你知吗?《死磕MySQL系列 七》

无法复现的“慢”SQL《死磕MySQL系列 八》

什么?还在用delete删除数据《死磕MySQL系列 九》

MySQL统计总数就用count(*),别花里胡哨的《死磕MySQL系列 十》

文章总目录

一、几大索引失效原因

你肯定在网上看到过非常多关于索引失效原因的文章,但是一定要自己亲手尝试一下,因为版本不同引发的结果不会一致。

1.带头大哥不能死

这局经典语句是说创建索引要符合最左侧原则。

例如表结构为u_id,u_name,u_age,u_sex,u_phone,u_time

创建索引为idx_user_name_age_sex

查询条件必须带上u_name这一列。

2.不在索引列上做任何操作

不在索引列上做任何计算、函数、自动或者手动的类型转换,否则会进行全表扫描。简而言之不要在索引列上做任何操作。

3.俩边类型不等

例如建立了索引idx_user_name,name字段类型为varchar

在查询时使用where name = kaka,这样的查询方式会直接造成索引失效。

正确的用法为where name = “kaka”。

4.不适当的like查询会导致索引失效

创建索引为idx_user_name

执行语句为select * from user where name like “kaka%”;可以命中索引。

执行语句为select name from user where name like “%kaka”;可以使用到索引(仅在8.0以上版本)。

执行语句为select * from user where name like ‘’%kaka";会直接导致索引失效

5.范围条件之后的索引会失效

创建索引为idx_user_name_age_sex

执行语句select * from user where name = ‘kaka’ and age > 11 and sex = 1;

上面这条sql语句只会命中name和age索引,sex索引会失效。

复合索引失效需要查看key_len的长度即可。

总结:%在后边会命令索引,当使用了覆盖索引时任何查询方式都可命中索引。

以上就是咔咔关于索引失效会出现的原因总结,在很多文章中没有标注MySQL版本,所以你有可能会看到is null 、or索引会失效的结论。

二、从规则方面说明索引失效的原因

问题的答案就是第3点,两边类型不一致导致索引失效。

下图是表结构,目前这个表存在两个索引,一个主键索引,一个普通索引phone。

分别执行以下两条SQL语句

explain select * from evt_sms where phone = 13020733815;

explain select * from evt_sms where phone = '13020733815';

在这里插入图片描述

从上图可看出,执行第一条SQL没有使用到索引,第二条SQL却使用到了索引。

不错,你也发现了两条SQL的不同,第二条SQL跟第一条SQL逻辑一致,不同的是一个查询条件有引号,一个没有。

问题:为什么逻辑相同的SQL却是用不了索引

选择索引是优化器大哥的工作,大哥做事肯定轮不到咱们去教,因为大哥有自己的一套规则。

对于优化器来说,如果等号两边的数据类型不一致,则会发生隐式转换。

例如,explain select * from evt_sms where phone = 13020733815;这条SQL语句就会变为explain select * from evt_sms where cast(phone as signed int) = 13020733815;

由于对索引列进行了函数操作,从而导致索引失效。

问题:为什么会把左侧的列转为int类型呢?

优化器大哥就是根据这个规则进行判断,是把字符串转为数字,还是把数字转为字符串。

若返回1,则把字符串转为数字。

若返回0,则把数字转为字符串。

问题:select * from evt_sms where id = "193014410456945216"这条SQL语句能用上索引吗?

如果你忘记了表结构,可以翻到文章开头再看下表evt_sms的索引。

可以知道列id添加了主键索引,类型为int类型。

根据规则得到,MySQL8.0以上的版本是将字符串转为数字。

所以说,函数操作的是等号右边的数据,跟索引列没有关系,所以可以用上索引。

那么来到数据库验证一下结论,你答对了吗?

三、从索引结构说明索引失效原因

有这样一个需求,要统计每年双11注册用户数量。

可以看到在evt_sms表中是没有给create_time创建索引的,于是你会执行alter table evt_sms add index idx_ctime(create_time),给create_time添加上索引。

接着你就执行了下面的SQL语句。

explain select count(*) from evt_sms where month(create_time) = 11;

上线没一会数据库出现了大量的慢查询,导致非常多的SQL返回失败。

此时公司大牛肯定会直接指出问题,索引列进行函数操作。

问题:为什么索引列使用函数就用不上索引了呢?

你现在看到的create_time索引结构图。

若此时执行的是where create_time = ‘2021-11-16’,那么MySQL就会非常快的等位到对应位置,并返回结果。

但是,做了函数操作,例如month(2021-11-16)得到的值是11。

当MySQL拿到返回的这个11时,在索引结构中根据就不知道怎么办。MySQL之所以能使用快速定位,是因为B+树的有序性。

而使用了函数对索引列进行操作后就会破坏索引的有序性,因此优化器大哥会选择执行代价最低的索引来继续执行。

四、结论

本期文章给大家介绍了两个案例,一个隐式转换,一个对索引列进行函数操作。

两种情况的本质是一样的,都是在索引列上进行了函数操作,导致全表扫描。

类似于这两种情况的还是字符集问题,不过一般这个问题会会很少发生,如有新业务需要新创建表,都会设置为之前的字符集。

两张表的字符集不同在进行join时也会导致隐式字符集转换,导致索引失效。

坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念。愿文章在偌大的互联网上能给你带来一点帮助,我是咔咔,下期见。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么MySQL字符串不加引号索引失效?《死磕MySQL系列 十一》 的相关文章

  • 通过 JDBC 将“daterange”字段值插入 PostgreSQL 表

    我在 PostgreSQL 9 3 有一个表日期范围 http www postgresql org docs 9 3 static rangetypes html字段类型 我可以像使用 JDBC 的字符串一样选择此字段 但无法将其插入表中
  • 通过货币换算获取每种产品类型的最低价格

    我想选择每种产品类型中最便宜的 包括运费 价格转换为当地货币 最便宜 产品 价格 产品 运费 seller to aud 我的数据库有如下表 PRODUCTS SELLERS id type id seller id price shipp
  • C#:SQL 查询生成器类

    在哪里可以找到好的 SQL 查询构建器类 我只需要一个简单的类来构建 SQL 字符串 仅此而已 我需要它用于 C 和 MySql 我真的不需要像 Linq 或 NHibernate 这样的东西 谢谢 由于 Google 将我引导至此页面 我
  • 将 UPDATE 转换为 INSERT INTO ON DUPLICATE KEY UPDATE 语句

    我有这个 UPDATE MySQL 语句 效果很好 UPDATE table1 Inner Join table2 ON table2 id table1 gw id SET table1 field1 1 table1 field2 2
  • MySQL+子串怎么做? + 替换?

    我不太擅长 SQL 希望能够变得更好 我在尝试执行某些表操作时遇到一些麻烦 我希望能够从下面的 ProgUID 列中选择子字符串 就像是 SUBSTRING table ProgUID 3 12 这将为我提供 ProgUID P CAMVE
  • 通过连接从两个表中删除?

    我有两个表如下 tbl1 tbl2 id article id title image whole news tags author older datetime 其中 tbl1 id gt tbl2 article id 如何从两个表中删
  • MySQL 全文搜索不适用于某些单词,例如“house”

    我已经在 3 个字段中的一小部分记录上设置了全文索引 也尝试了 3 个字段的组合 并得到了相同的结果 有些单词返回结果很好 但某些单词如 house 和 澳大利亚 不这样做 有趣的是 澳大利亚 和 家乡 这样做 这似乎是奇怪的行为 如果我添
  • 使用 Greasemonkey 时存储数据

    使用 Greasemonkey 时是否有存储大量数据的好方法GM setValue只是没有削减它 那么这里有一些选项 设置服务器来保存数据 对于用户 并使用 xhr 来 创建 编辑 删除数据 谷歌应用程序 发动机 GAE http code
  • 如何将 MySQL 数据库更改为 UTC?

    我使用的是 Windows 7 对数据库方面的东西有点陌生 我尝试在 Google 上搜索如何将系统时区更改为 UTC 但文档有些高级 我不太确定如何更改此字段 在 my ini 文件的 mysqld 部分下 添加以下行 default t
  • 单行的总和值?

    我有一个 MySQL 查询 它返回由一系列 1 和 0 组成的单行 它用于进度条指示器 我现在在代码中对它进行求和 但我尝试对查询中的值求和 并意识到我无法使用 SUM 因为它们有很多列 但只有一行 有没有办法可以在查询中自动求和 就像这样
  • MySQL 存储过程将值分配给 select 语句中的多个变量

    这是我的存储过程 我在为声明的变量赋值时遇到问题 当我执行它时 插入和更新命令工作正常 但声明变量的值保持为 0 但我在数据库中有一些价值 我怎样才能正确地做到这一点 BEGIN DECLARE PaidFee INT DEFAULT 0
  • 在 MacOSX10.6 上运行 python 服务器时 MySQLdb 错误

    运行我的服务器 python manage py runserver 产生以下错误 django core exceptions ImproperlyConfigured 加载 MySQLdb 模块时出错 没有名为 MySQLdb 的模块
  • ActiveRecord3死锁重试

    Rails 3 或 ActiveRecord 3 是否有任何插件可以复制旧版本死锁重试 http agilewebdevelopment com plugins deadlock retry插入 或者 该插件仍然适用于 Rails 3 吗
  • 什么是数据库池?

    我只是想了解数据库连接池的概念以及它是如何实现的 数据库联系池是一种用于保持数据库连接打开的方法 以便其他人可以重用它们 通常 打开数据库连接是一项昂贵的操作 尤其是在数据库位于远程的情况下 您必须打开网络会话 进行身份验证 检查授权等等
  • Hibernate 对集合的查询过滤器

    我想执行以下查询 from Item i where i categoryItems catalogId catId 然而 这会产生以下异常 非法尝试取消引用集合 所以我用谷歌搜索 找到了这个 Hibernate 论坛帖子https for
  • 为什么这会返回资源 id #2? [复制]

    这个问题在这里已经有答案了 可能的重复 我如何从 PHP 中的 MySql 响应中 回显 资源 id 6 https stackoverflow com questions 4290108 how do i echo a resource
  • 如何在不运行 PostgreSQL 服务器的情况下初始化 PostgreSQL 数据库

    在初始化脚本中 我想初始化 PostgreSQL 目录 但在此阶段不需要 也不希望 正在运行的 PostgreSQL 服务器 如果我只是创建集群 作为用户postgres initdb D 但是 我还需要创建 PostgreSQL 角色 创
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • 忽略重复条目并在 EF Core 中的 DbContext.SaveChanges() 上提交成功条目

    我有一个 ASP Net Core 2 2 Web API 在我的一个控制器操作中 我向 MySQL 数据库表添加了一堆行 我使用的是 Pomelo 例如 dbContext AddRange entities dbContext Save
  • 将第三个表链接到多对多关联中的桥接表

    设计这个数据库的正确方法是什么 这是我设置表格的方式 我在名为 教师 的表和名为 仪器 的表之间存在多对多关系 然后我有一个连接两者的桥接表 我想将另一个表与 BRIDGE 表关联起来 意思是乐器 老师的组合 该表有 3 行 指定老师可以教

随机推荐

  • linux系统忘记记密码怎么办

    linux 此次操作系统为 CentOS Linux release 7 5 1804 Core 1 重启linux 进入系统的GRUB菜单界面 按下小写字母e进入编辑界面 进入如下画面 2 按下方向键 找到以字符串Linux16开头的行
  • 物联网改造体育产业,这些常见球类都成了数据终端

    从智能手机 衣服 汽车到冰箱 物联网意味着几乎任何物件都可以连接到网络 通过物件里含有的传感器之间的通信和同步 我们获得了大量的数据 这些数据经过分析和处理 产生了大数据智能 现在 物联网 大数据智能不仅仅是一种时尚 一个流行语 更将彻底改
  • pppoe 拨号过程

    PPPoE 拔号过程 发现阶段解析 文档编号 834 浏览 14295 评分 73 最后更新于 2011 02 11 PPPoE拔号的发现阶段 Discovery PPPoE的发现阶段一共分为 4步 分别是 PADI PPPoE Activ
  • 什么是图神经网络

    2019年可以说是图神经网络元年 01 什么是图神经网络 1 图和属性图 要了解图神经网络 首先要了解图 图是由节点和边组成的 如下图所示 一般图中的节点表示实体对象 比如一个用户 一件商品 一辆车 一张银行卡等都可以作为节点 边代表事件或
  • 服务器windows操作系统安装,服务器windows操作系统的安装.doc

    服务器windows操作系统的安装 Windows 2K3 2K8系统的安装 注 在这两个操作系统的安装中尤其要注意RAID卡驱动的加载 Windows server 2003标准版的安装 一 准备工作 Windows 2003标准版的安装
  • Unity之三:配置向导

    文章目录 一 C标准 编译器 微控制器 二 选项 2 1 整数类型 2 1 1 UNITY EXCLUDE STDINT H 2 1 2 UNITY EXCLUDE LIMITS H 2 1 3 UNITY INT WIDTH 2 1 4
  • 项目重构之起始

    百层之台始于累土 合抱之木生于毫末 转眼间来到公司已历三个寒暑 愈加光亮鬓角 隆起的肚腩 无不彰显着开发功力日渐深厚 公司的产品也从H5商城成长为了一款app 步入了他的青年阶段 也许是青春期的原因 也许是成长路上各种功能迭代导致 总而言之
  • Keil5(MDK5)在调试(debug)过程中遇到的问题

    参考原子哥教程 使用开发板 STM32F103RC Keil5 MDK5 在调试 debug 过程中崩溃 IDE已停止运行 http blog csdn net qq 33259138 article details 70224581 现象
  • Py的ipykernel:Python库介绍、安装及使用攻略

    Py的ipykernel Python库介绍 安装及使用攻略 ipykernel是一个用于在Jupyter Notebook中运行Python代码的包 它可以将Python代码转化为可以在IPython内核上运行的格式 下面我们将详细介绍如
  • C/C++中如何获取数组的长度?

    C C 中没有提供 直接获取数组长度的函数 对于存放字符串的字符数组提供了一个strlen函数获取长度 那么对于其他类型的数组如何获取他们的长度呢 其中一种方法是使 用sizeof array sizeof array 0 在C语言中习惯上
  • ctfhub技能树部分wp(潦草笔记)

    备份文件下载 vim缓存 在使用vim时会创建临时缓存文件 关闭vim时缓存文件则会被删除 当vim异常退出后 因为未处理缓存文件 导致可以通过缓存文件恢复原始文件内容 隐藏文件index php swp前加 以 index php 为例
  • 仿牛客网项目第三章:开发社区核心功能(详细步骤和思路)

    目录 1 过滤敏感词 1 1 目的 1 2 实现方法 1 3 前缀树 1 4 敏感词过滤步骤 为发帖子做准备 2 发布帖子 2 1 AJAX介绍 2 2 AJAX使用实例 3 帖子详情 3 1 实现功能 3 2 实现过程 4 事务管理 4
  • little endian && big-endian

    java 的ClassFile采用big endian存储数据 Intel x86 采用little endian Motorola采用big endian 0x1234 Intel 地址 0x4000 0000 0x34 0x4000 0
  • vue-使用sass定义全局样式及变量

    vue cli2使用sass定义全局样式及变量 vue cli2创建的vue项目使用sass预处理器需按顺序安装以下插件 其中sass loader版本和node sass需要安装固定版本 其他的依赖不要求版本 亲测有效 如果不不固定sas
  • unity Domain Reload & scene Reload 静态变量重置

    关闭 Domain Reload 选项后 c 的静态变量在下次运行时不会怎么重置 需要手动添加重置代码 使用下面的属性设置重置变量函数 using UnityEngine public class StaticCounterExampleF
  • ns.ajax,UIWebView使用NSURLProtocol(拦截),ajax加载失败的问题

    问题 ajax跨域访问是一个老问题了 解决方法很多 比较常用的是JSONP方法 JSONP方法是一种非官方方法 而且这种方法只支持GET方式 不如POST方式安全 即使使用jquery的jsonp方法 type设为POST 也会自动变为GE
  • 解决eclipse新建dynamic web project没有apache的Runtime environment问题

    在新建eclipse web项目时候 想选择Tomact服务器 不过运行时环境选择中没有 没有出现下图的Apache目录吗 网络上好像没有找到教程 其实很简单 只是没有装上相应的插件 解决步骤如下 1 打开Help gt Install N
  • ThinkPad BIOS 设置详解

    ThinkPad BIOS 设置详解 ThinkPad BIOS 设置详解 主流 新机型 在网上查看了相关资料 发现好多都是T40或者更老的BIOS设置信息 不适合现在的主流以及新机型 于是找到分享该贴 希望对各位有所帮助 简洁的分割线 T
  • Python-错误与异常处理

    通常情况下 在try语句块中写我们想要的逻辑 发生错误和异常时Python解释器会采用raise方法即将异常抛出 except语句可以承接raise方法抛出的异常并对异常做出处理 Python中有三种异常捕获与处理形式 第一种 try ex
  • 为什么MySQL字符串不加引号索引失效?《死磕MySQL系列 十一》

    群里一个小伙伴在问为什么MySQL字符串不加单引号会导致索引失效 这个问题估计很多人都知道答案 没错 是因为MySQL内部进行了隐式转换 本期文章就聊聊什么是隐式转换 为什么会发生隐式转换 文章目录 系列文章 一 几大索引失效原因 二 从规