您当前的位置:首页 > 电脑百科 > 数据库 > 百科

这些个索引坑,你们是否有踩过呢?

时间:2020-08-24 16:53:53  来源:  作者:

做业务开发的同学都知道,有些SQL看起来没啥问题,索引也用到了,但就是很慢.......

今天我们来通过几个常见的例子来深入探究下SQL慢的原因

案例一

假设你现在维护了一个帖子表,包含帖子id(tweet_id)、用户id(user_id)、时间(gmt_create)等字段。为了便于描述,我们先忽略其他字段。这个表的建表语句如下:

MySQL> CREATE TABLE `t_tweet` (
  `id` int(11) NOT NULL,
  `tweet_id` varchar(32) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `tweet_id` (`tweet_id`),
  KEY `gmt_create` (`gmt_create`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
复制代码

假设,现在已经记录了从2016年初到2018年底的所有数据,有一个需求是,要统计发 生在所有年份中7月份的帖子记录总数。这个逻辑看上去并不复杂,你的SQL语句可能会这么 写:

select count(*) from t_tweet where month(gmt_create)=7;
复制代码

由于gmt_create字段上有索引,于是你就很放心地在生产库中执行了这条语句,但却发现执行了 特别久,才返回了结果。

如果你问DBA同事为什么会出现这样的情况,他大概会告诉你:如果对字段做了函数计算,就 用不上索引了,这是MySQL的规定。

如果你已经学过了InnoDB的索引结构了,可以再追问一句,为什么?

为什么条件是where gmt_create='2018-7-1’的时候可以用上索引,而改成where month(gmt_create)=7的时候就不行了?

下面是这个gmt_create索引的示意图。方框上面的数字就是month()函数对应的值。

这些个索引坑,你们是否有踩过呢?

 

如果你的SQL语句条件用的是where gmt_create='2018-7-1’的话,引擎就会按照上面绿色箭头的 路线,快速定位到 gmt_create='2018-7-1’需要的结果。

实际上,B+树提供的这个快速定位能力,来源于同一层兄弟节点的有序性。

但是,如果计算month()函数的话,你会看到传入7的时候,在树的第一层就不知道该怎么办了。 也就是说,对索引字段做函数操作, 可能会破坏索引值的有序性, 因此优化器就决定放弃 走树搜索功能。

需要注意的是,优化器并不是要放弃使用这个索引。

在这个例子里,放弃了树搜索功能,优化器可以选择遍历主键索引,也可以选择遍历索引 gmt_create,优化器对比索引大小后发现,索引gmt_create更小,遍历这个索引比遍历主键索引 来得更快。因此最终还是会选择索引gmt_create。 可以使用explain命令,查看一下这条SQL语句的执行结果

key="gmt_create"表示的是,使用了gmt_create这个索引;我在测试表数据中插入了10万行数 据,rows=100335,说明这条语句扫描了整个索引的所有值;Extra字段的Using index,表示的是使用了覆盖索引。

也就是说,由于在gmt_create字段加了month()函数操作,导致了全索引扫描。

到这里我给你说明了,由于加了month()函数操作,MySQL无法再使用索引快速定位功能,而只能使用全索引扫描。

优化器在某些问题上确实有“偷懒”行为,即使是对于不改变有序性的函数,也不会考虑使用索 引。

比如,对于select * from t_tweet where id + 1 = 10000这个SQL语句,这个加1操作并不会改变有序性,但是MySQL优化器还是不能用id索引快速定位到9999这一行。所以,需要你在写 SQL语句的时候,手动改写成 where id = 10000 -1才可以。

案例二

我们一起看一下这条SQL语句:

select * from t_tweet where tweet_id=110717;
复制代码

交易编号tweet_id这个字段上,本来就有索引,但是explain的结果却显示,这条语句需要走全表 扫描。你可能也发现了,tweet_id的字段类型是varchar(32),而输入的参数却是整型,所以需要做类型转换。

那么,现在这里就有两个问题:

  1. 数据类型转换的规则是什么?
  2. 为什么有数据类型转换,就需要走全索引扫描?

先来看第一个问题,你可能会说,数据库里面类型这么多,这种数据类型转换规则更多,我记不 住,应该怎么办呢? 这里有一个简单的方法,看 select “10” > 9的结果:

  1. 如果规则是“将字符串转成数字”,那么就是做数字比较,结果应该是1;
  2. 如果规则是“将数字转成字符串”,那么就是做字符串比较,结果应该是0。

这时,你再看这个全表扫描的语句:

select * from t_tweet where tweet_id=110717;
复制代码

就知道对于优化器来说,这个语句相当于:

select * from t_tweet where CAST(tweet_id AS tweetId int) = 110717;
复制代码

也就是说,这条语句触发了我们上面说到的规则:对索引字段做函数操作,优化器会放弃走树搜 索功能。

案例三

假设系统里还有另外一个表tweet_detail,用于记录帖子的详情数据。

mysql> CREATE TABLE `t_tweet_detail` (
  `id` int(11) NOT NULL,
  `tweet_id` varchar(32) DEFAULT NULL,
  `author_id` int(11) DEFAULT NULL, /* 帖子作者id*/
  `tweet_info` varchar(32) DEFAULT NULL, /* 帖子内容 */
  PRIMARY KEY (`id`),
  KEY `tweet_id` (`tweet_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码

这时候,如果要查询id=2的帖子的所有信息,SQL语句可以这么写:

select d.* from t_tweet l, t_tweet_detail d where t1.tweet_id=t2.tweet_id and t2.id=2; 
复制代码

explain的结果里面第二行的key=NULL表示的就是,这个过程是通过遍历主键索引的方式,一个一个地判断tweet_id的值是否匹配。

表示没有用上帖子详情表t_tweet_detail上的tweet_id索引,进行了全表扫描。

进行到这里,你会发现第3步不符合我们的预期。因为表t_tweet_detail里tweet_id字段上是有索引 的,我们本来是希望通过使用tweet_id索引能够快速定位到等值的行。但,这里并没有。

如果你去问DBA同学,他们可能会告诉你,因为这两个表的字符集不同,一个是utf8,一个是 utf8mb4,所以做表连接查询的时候用不上关联字段的索引。

这个回答,也是通常你搜索这个问 题时会得到的答案。 但是你应该再追问一下,为什么字符集不同就用不上索引呢?

结论是:字符集utf8mb4是utf8的超集,所以当这两个类型的字 符串在做比较的时候,MySQL内部的操作是,先把utf8字符串转成utf8mb4字符集,再做比较。

这个设定很好理解,utf8mb4是utf8的超集。类似地,在程序设计语言里面,做自动类型转换 的时候,为了避免数据在转换过程中由于截断导致数据错误,也都是“按数据长度增加的方 向”进行转换的。

因此, 在执行上面这个语句的时候,需要将被驱动数据表里的字段一个个地转换成utf8mb4

这就再次触发了我们上面说到的原则:对索引字段做函数操作,优化器会放弃走树搜索功能。

优化:把t_tweet_detail表上的tweet_id字段的字符集也改成utf8mb4,这样就 没有字符集转换的问题了。


原文链接:https://juejin.im/post/6860513755000733709



Tags:索引   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
今天不讲信息流,讲点其他的,比如搜索搜索是什么东西?见过开店卖东西吧,原理大同小异。比如我在步行街租个店铺,开个鞋店,每天在店里等着来步行街的人进我店里买我的鞋。百度搜索就...【详细内容】
2021-12-24  Tags: 索引  点击:(9)  评论:(0)  加入收藏
话说C是面向内存的编程语言。数据要能存得进去,取得出来,且要考虑效率。不管是顺序存储还是链式存储,其寻址方式总是很重要。顺序存储是连续存储。同质结构的数组通过其索引表...【详细内容】
2021-12-08  Tags: 索引  点击:(17)  评论:(0)  加入收藏
一、背景介绍在网上冲浪少不了用到搜索引擎,而很多朋友都习惯把Google视为第一个选择对象。当然Google无论在搜索速度还是结果关联性方面都是十分优秀的。但百度(http://www.b...【详细内容】
2021-11-05  Tags: 索引  点击:(31)  评论:(0)  加入收藏
在SEO优化的职业里,运用搜索引擎对网页内容的检索原理,对网站内部外部资源进行优化整合,然后到达抱负的作用,便利客户快速找到想要的信息。在分类上也可分白帽SEO和黑帽SEO。一...【详细内容】
2021-10-22  Tags: 索引  点击:(36)  评论:(0)  加入收藏
网络推广计划表示在网站优化时,内容优化也是重中之重,其中有关文章的优化也让站长们苦恼不已,因为不太清楚蜘蛛对网站文章的质量评判是如何的,很难做到更精准的蜘蛛“取向”,那么...【详细内容】
2021-10-22  Tags: 索引  点击:(45)  评论:(0)  加入收藏
一,概述 一般而言,我们对关系型数据库系统,进行表结构设计时,会按数据的种类,进行分类,一般有如下种类: 1)主数据,其数据量基本稳定,不随时间而线性增长。比如,分公司,产品,经销商。...【详细内容】
2021-10-19  Tags: 索引  点击:(42)  评论:(0)  加入收藏
前言:我们都知道,当执行 select 查询语句时,用没用到索引区别是很大的,若没用到索引,一条 select 语句可能执行好几秒或更久,若使用到索引则可能瞬间完成。那么当执行 update 语句...【详细内容】
2021-09-07  Tags: 索引  点击:(49)  评论:(0)  加入收藏
搜索引擎是公众获取信息的重要渠道,也是众多企业进行宣传营销的重要阵地。而随着“有偿删帖”入刑,通过各种“非删除”方式进行网络负面舆论压制也成为相关行业的主流操作。...【详细内容】
2021-09-07  Tags: 索引  点击:(62)  评论:(0)  加入收藏
生产上偶现这段代码会出现死锁,死锁日志如下。*** (1) TRANSACTION:TRANSACTION 424487272, ACTIVE 0 sec fetching rowsmysql tables in use 3, locked 3LOCK WAIT 6 lock s...【详细内容】
2021-07-29  Tags: 索引  点击:(65)  评论:(0)  加入收藏
作为一名专业的SEO从业者,对于任何SEO项目的推进,都是建立在搜索策略基础之上,因此,定期关注搜索动态是一个必修课,只有这样我们才能更好的制定优化策略。比如:百度本次升级蓝天算...【详细内容】
2021-07-28  Tags: 索引  点击:(72)  评论:(0)  加入收藏
▌简易百科推荐
1增1.1【插入单行】insert [into] <表名> (列名) values (列值)例:insert into Strdents (姓名,性别,出生日期) values (&#39;开心朋朋&#39;,&#39;男&#39;,&#39;1980/6/15&#3...【详细内容】
2021-12-27  快乐火车9d3    Tags:SQL   点击:(1)  评论:(0)  加入收藏
最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫, 不知道各种写法孰优孰劣,该选用哪种写法,以及各种写法的优缺点,本文以一个简单的查询...【详细内容】
2021-12-23  linux上的码农    Tags:sql   点击:(9)  评论:(0)  加入收藏
《开源精选》是我们分享Github、Gitee等开源社区中优质项目的栏目,包括技术、学习、实用与各种有趣的内容。本期推荐的HasorDB 是一个全功能数据库访问工具,提供对象映射、丰...【详细内容】
2021-12-22  GitHub精选    Tags:HasorDB   点击:(5)  评论:(0)  加入收藏
作者丨Rafal Grzegorczyk译者丨陈骏策划丨孙淑娟【51CTO.com原创稿件】您是否还在手动对数据库执行各种脚本?您是否还在浪费时间去验证数据库脚本的正确性?您是否还需要将...【详细内容】
2021-12-22    51CTO  Tags:Liquibase   点击:(3)  评论:(0)  加入收藏
场景描述:由于生产环境的表比较复杂,字段很多。这里我们做下简化,只为说明今天要聊的问题。有两张表 tab1,tab2: tab1 数据如下: tab2 数据如下: 然后给你看下,我用来统计 name=&#3...【详细内容】
2021-12-20  Bald    Tags:SQL   点击:(5)  评论:(0)  加入收藏
前言知识无底,学海无涯,知识点虽然简单,但是比较多,所以将MySQL的基础写出来,方便自己以后查找,还有就是分享给大家。一、SQL简述1.SQL的概述Structure Query Language(结构化查...【详细内容】
2021-12-16  谣言止于独立思考    Tags:SQL基础   点击:(13)  评论:(0)  加入收藏
前言作为一名测试工程师,工作中在对测试结果进行数据比对的时候,或多或少要和数据库打交道的,要和数据库打交道,那么一些常用的 SQL 查询语法必须要掌握。最近有部分做测试小伙...【详细内容】
2021-12-14  柠檬班软件测试    Tags:SQL   点击:(15)  评论:(0)  加入收藏
话说C是面向内存的编程语言。数据要能存得进去,取得出来,且要考虑效率。不管是顺序存储还是链式存储,其寻址方式总是很重要。顺序存储是连续存储。同质结构的数组通过其索引表...【详细内容】
2021-12-08  小智雅汇    Tags:数据存储   点击:(17)  评论:(0)  加入收藏
概述DBConvert Studio 是一款强大的跨数据库迁移和同步软件,可在不同数据库格式之间转换数据库结构和数据。它将成熟、稳定、久经考验的 DBConvert 和 DBSync 核心与改进的现...【详细内容】
2021-11-17  雪竹聊运维    Tags:数据库   点击:(26)  评论:(0)  加入收藏
一、前言 大家好,我是小诚,《从0到1-全面深刻理解MySQL系列》已经来到第四章,这一章节的主要从一条SQL执行的开始,由浅入深的解析SQL语句由客户端到服务器的完整执行流程,最...【详细内容】
2021-11-09  woaker    Tags:SQL   点击:(35)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条