详解mysql什么时候不走索引

全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上不计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写 *;
不等空值还有or,索引失效要少用;
字符单引不可丢,SQL高级也不难 ;

索引的种类

众所周知,索引类似于字典的目录,可以提高查询的效率。

索引从物理上可以分为:聚集索引,非聚集索引

从逻辑上可以分为:普通索引,唯一索引,主键索引,联合索引,全文索引

索引优化策略

面试必备,MySQL索引优化实战总结,涵盖了几乎所有索引注意事项

不要在索引列上进行运算或使用函数

在列上进行运算或使用函数会使索引失效,从而进行全表扫描。如下面例子在publish_time,id列上分别加上索引,publish_time为datetime类型,id为int类型

-- 全表扫描
select * from article where year(publish_time) < 2019
-- 走索引
select * from article where publish_time < '2019-01-01'
-- 全表扫描
select * from article where id + 1 = 5
-- 走索引
select * from article where id = 4

小心隐式类型转换

假设id为varchar类型

-- 全表扫描
select * from article where id = 100
-- 走索引
select * from article where id = '100'

为什么呢?

select * from article where id = 100
-- 等价于
select * from article where CAST(id AS signed int) = 100

上一条规则说过,不要在索引列上使用函数,隐式类型转换在索引字段上做了函数操作,因此会全表扫描

那么如果id是int,执行下面这个语句是否会导致全表扫描呢?

select * from article where id = '100'

答案是会用到索引

前导模糊查询不会使用索引

-- 全表扫描
select * from article where author like '%李'

%李,%李%都会导致全表扫描,非前导模糊查询可以使用索引

-- 走索引
select * from article where author like '李%'

面试必备,MySQL索引优化实战总结,涵盖了几乎所有索引注意事项

联合索引最左前缀原则

mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整

1.将区分度最高的字段放在最左边

当不需要考虑排序和分组时,将区分度最高的列放在前面通常是很好的。这时候索引的作用只是用于优化WHERE条件的查找

如果在a b列上建立联合索引,该如何建立,才能使查询效率最高

select count(distinct a) / count(*), count(distinct b) / count(*), count(*) from table

执行如下语句,假设3个输出依次为0.001,0.373,16049,可以看到b列的选择性最高,因此将其作为联合索引的第一列,即建立(b, a)的联合索引

2.查询时=可以乱序

如果建立了联合索引(a, b)。例如下面的2个写法是等价的,因为MySQL会将查询的顺序优化成和联合索引的顺序一致

select * from table where a = '1' and b = '1'select * from table where b = '1' and a = '1'

3.优化查询,避免出现filesort

select * from table where a = ? and b = ? order by c

最左前缀原则不仅用在查询中,还能用在排序中。MySQL中,有两种方式生成有序结果集:

  1. 通过有序索引顺序扫描直接返回有序数据
  2. Filesort排序,对返回的数据进行排序

因为索引的结构是B+树,索引中的数据是按照一定顺序进行排列的,所以在排序查询中如果能利用索引,就能避免额外的排序操作。EXPLAIN分析查询时,Extra显示为Using index。

所有不是通过索引直接返回排序结果的操作都是Filesort排序,也就是说进行了额外的排序操作。EXPLAIN分析查询时,Extra显示为Using filesort,当出现Using filesort时对性能损耗较大,所以要尽量避免Using filesort

对于如下sql

select * from table where a = ? and b = ? order by c

可以建立联合索引(a, b, c)

如果索引中有范围查找,那么索引有序性无法利用,如

select * from table where a > 10 order by b

索引(a,b)无法排序。

放几个例子

-- 使用了a列
where a = 3-- 使用了a b列
where a = 3 and b = 5-- 使用了a b c列
where a = 3 and c = 4 and b = 5-- 没有使用索引
where b = 3-- 使用了a列 
where a = 3 and c = 4-- 使用了a b列 
where a = 3 and b > 10 and c = 7-- 使用了a b 列
where a = 3 and b like 'xx%' and c = 7unionorin都能命中索引,建议使用in

新版MySQL的or可以命中索引

select * from article where id = 1 or id = 2

效率从高到低为union,in,or。in和union的效率差别可以忽略不计,建议使用in

负向条件索引不会使用索引,建议用in

负向条件有:!=、<>、not in、not exists、not like 等

-- 全表扫描
select * from article where id != 1 and id != 2

知道id的所有取值范围,可以改为类似如下形式

-- 走索引
select * from article where id in (0, 3, 4)

建立覆盖索引
众所周知,表数据是放在一个聚集索引上的,而建立的索引为非聚集索引,非聚集索引的叶子节点存放索引键值,以及该索引键指向的主键。一般查找的过程是从非聚集索引上找到数据的主键,然后根据该主键到聚集索引上查找记录,这个过程称为回表,不清楚的看推荐阅读。

如有下面这个sql

select uid, login_time from user where username = ? and passwd = ?

可以建立(username, passwd, login_time)的联合索引,由于 login_time的值可以直接从索引中拿到,不用再回表查询,提高了查询效率

经常更改,区分度不高的列上不宜加索引

更新会变更 B+ 树,更新频繁的字段建立索引会大大降低数据库性能。

“性别”这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似。

一般区分度在80%以上的时候就可以建立索引,区分度可以使用 count(distinct(列名))/count(*) 来计算

明确知道只会返回一条记录,可以加limit1

当查询确定只有一条记录时,可以加liimit1,让MySQL停止游标移动,提高查询效率

select uid from user where username = ? and passwd = ?

可改为

select uid from user where username = ? and passwd = ? limit 1

对文本建立前缀索引

用邮箱登录是一个常见的问题,如果对email整个字段建立索引,会让索引变得大且慢

select username from user where email='xxx'; 

这时我们可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率,但这样也会降低索引的区分度。索引的区分度是指,不重复的索引值和数据表的记录总数的比值。索引的区分度越高则查询效率越高,因为区分度高的索引可以让MySQL在查找时过滤掉更多的行。

因此我们选择足够长的前缀保证较高的区分度,同时又不能太长(以便节约空间)

可以进行如下实验

select count(distinct left(email, 5)) / count(*) as col5,count(distinct left(email, 6)) / count(*) as col6,count(distinct left(email, 7)) / count(*) as col7from user

假设输出依次为0.0305,0.0309,0.0310

查询显示当前缀长度达到7的时候,再增加前缀长度,区分度提升的幅度已经很小了,因此创建email(7)的前缀索引即可

需要注意的一点是,前缀索引不能使用覆盖索引,因为从索引中获取不到完整的数据,还得回表查询

建立索引的列不为NULL

只要列中包含有 NULL 值都将不会被包含在索引中,复合索引中只要有一列含有 NULL值,那么这一列对于此复合索引就是无效的。

因此,在数据库设计时,除非有一个很特别的原因使用 NULL 值,不然尽量不要让字段的默认值为 NULL。

分页查询优化

MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写,单开一文来讲

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unbuntu cmake安装mysql_ubuntu下编译安装mysql5.5

1.主要步骤如下添加mysql用户和用户组—>下载源码—>解压源码安装编译2个套件—>编译源码-安装编译好的程序-配置mysql启动服务2.Mysql源码解压建好相应的安装目录&#xff0c;将压缩文件复制到安装目录并解压。3.添加用户组Sudo groupadd mysql4.添加用户Sudo userad…

MYSQL中数据类型介绍

一、MySQL的数据类型 主要包括以下五大类&#xff1a; 整数类型&#xff1a;BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT 浮点数类型&#xff1a;FLOAT、DOUBLE、DECIMAL 字符串类型&#xff1a;CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、…

mysql删库后恢复_记一次MySQL删库的数据恢复

昨天因为不可描述的原因&#xff0c;数据库直接被 drop database删除。在第一时间停止数据库服务和Web服务&#xff0c;备份MySQL数据目录下的所有文件之后&#xff0c;开始走上数据恢复之路。第一次干这种事&#xff0c;各种不得法。因为我们既没有备份&#xff0c;也没有开启…

mysql中数据类型的长度

一、varchar&#xff08;n&#xff09;、char(n)中的n的含义 1&#xff09;varchar(m),char(n)里面的m或n代表的是字符的个数。 打开mysql手册&#xff0c;看到这样一句话 The CHAR and VARCHAR types are declared with a length that indicates the maximum number of char…

mysql数据库操作宠物表_mysql数据库之表的操作

语法&#xff1a;1. 修改表名ALTER TABLE 表名RENAME 新表名;2. 增加字段ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…],ADD 字段名 数据类型 [完整性约束条件…];ALTER TABLE 表名ADD 字段名 数据类型 [完整性约束条件…] FIRST;ALTER TABLE 表名ADD 字段名 数据类…

Mysql 中的Text字段的范围

Mysql 中的Text字段的范围 text&#xff1a;存储可变长度的非Unicode数据&#xff0c;最大长度为2^31-1个字符。text列不能有默认值&#xff0c;存储或检索过程中&#xff0c;不存在大小写转换&#xff0c;后面如果指定长度&#xff0c;不会报错误&#xff0c;但是这个长度是不…

python实现语义分割_语义分割算法之FCN论文阅读及源码实现

论文原文创新点提出了一种端到端的做语义分割的方法&#xff0c;在这里插入图片描述如图&#xff0c;直接拿分割的ground truth作为监督信息&#xff0c;训练一个端到端的网络&#xff0c;让网络做p像素级别的预测。如何设计网络结构如何做像素级别的预测在这里插入图片描述在V…

记住:永远不要在MySQL中使用“utf8”,请使用“utf8mb4” 程序员

记住&#xff1a;永远不要在MySQL中使用“utf8”&#xff0c;请使用“utf8mb4” 最近我遇到了一个bug&#xff0c;我试着通过Rails在以“utf8”编码的MariaDB中保存一个UTF-8字符串&#xff0c;然后出现了一个离奇的错误&#xff1a; 我用的是UTF-8编码的客户端&#xff0c;服…

mysql——decimal类型与decimal长度

分为三种&#xff1a; float&#xff1a;浮点型&#xff0c;含字节数为4&#xff0c;32bit&#xff0c;数值范围为-3.4E38~3.4E38&#xff08;7个有效位&#xff09;double&#xff1a;双精度实型&#xff0c;含字节数为8&#xff0c;64bit&#xff0c;数值范围-1.7E308~1.7E3…

右上角的引用文献格式_论文要引用的小符号右上角怎么打?

上标是【现在】论【文的】书写【都会】【用到】引用【的小】符号&#xff0c;上标【一般】用【来对】所标的【文字】【或者】段落【进行】进【一步】【的解】释&#xff0c;【所以】常【用来】【解释】含义&#xff0c;【或者】出处&#xff0c;【而其】【解释】【一般】在书【…

java.util.function.Function的用法

JDK 1.8 API包含了很多内建的函数式接口&#xff0c;在老Java中常用到的比如Comparator或者Runnable接口&#xff0c;这些接口都增加了FunctionalInterface注解以便能用在lambda上。现如今&#xff0c;我们则从Function常用函数入口&#xff0c;真正了解一下。 nametypedescri…

mysql服务器程序_MySQL服务器

1、安装通常系统在成功安装之后就已经自带MySQL服务器以及客户端了。查询MySQL及其相关文件是否安装&#xff1a;rpm -qa | grep perlrpm -qa | grep mysql如果没有安装&#xff0c;则可以使用yum进行安装&#xff1a;yum -y install perl-DBIyum -y install perl-DBD-MySQLyum…

Java中List的contains方法,你用对了吗?

Java语言中的List是我们处理集合时经常会用到的。而List定义了一个contains方法&#xff0c;用以判断一个集合中是否包含指定的一个对象。 大家应该有用到过吧&#xff0c;可是你真的会用&#xff0c;用对了吗&#xff1f; 看看下面的代码。 上图代码中&#xff0c;创建了两个…

mysql sql in or 替换_sql IN 的用法一例--替换 mysql longtext字段中某些内容的用法

之前给改版的一个学校里的站点突然提出要求&#xff0c;说需要将之前编辑的文章的字体大小全部改成默认值。字体的控制无非有两种&#xff0c;一是font-size 16 px&#xff1b;然后是。但是&#xff0c;之前发布的文章&#xff0c;文字的控制是由编辑器生成的&#xff0c;而根…

List的contains方法使用

List的contains方法用于判断对象是否存在于列表中。 举例说明&#xff1a; 这里简单的创建一个User类&#xff1a; public class User {private String id;private String name;private String phone;private String address;//忽略getters和setters }在main方法中创建3个User…

mysql初体验学习笔记_【MySQL】mycli初体验

早就听说mycli很好用&#xff0c;今天打算在本地测试机上装一下体验一把。安装方法很是简单&#xff1a;一、安装依赖&#xff1a;yum install python-pip python-devel二、安装myclipip install mycli这样就安装完了。三、使用方法[rootlocalhost .pip]# mycli --helpUsage: m…

ArrayList类contains方法实现原理

以ArrayList集合示例 思考&#xff1a;contains方法如何执行&#xff1f; public static void main(String [] args){List<String> listnew ArrayList<String>(); list.add("张三"); System.out.println(list.contains("张三"); }分析contai…

mysql索引结构优缺点_mysql索引优缺点及注意事项

优点有了索引.对于记录数量很多的表,可以提高查询速度.缺点索引是占用空间的.索引会影响update insert delete速度ALERT!!!1 索引要创建在where和join用到的字段上.2 以下操作符号可以应用索引&#xff1a;&#xff0c;>&#xff0c;BETWEEN&#xff0c;IN&#xff0c…

Mybatis源码分析之(五)mapper如何将数据库数据转换成java对象的

本篇对mybatis从取到数据库数据开始到映射成对象并返回的过程进行了详细的分析。 转换ResultSet成java对象 下面的代码是PreparedStatementHandler中的 Overridepublic <E> Cursor<E> queryCursor(Statement statement) throws SQLException {PreparedStatement …

Java Stream Collectors.groupingBy()实现分组(单字段分组,多字段分组)

1 User实体类 public class User {private Long userId;/*** 用户名(登录)*/private String username;/*** 年龄*/private int age;/*** 性别*/private int sex;/*** 密码*/private String password; }2 单字段分组 //根据年龄分组 List<User> userList new ArrayList…