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

索引的种类

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

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

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

索引优化策略

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

在列上进行运算或使用函数会使索引失效,从而进行全表扫描。如下面例子在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会一直向右匹配直到遇到范围查询(>、<、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 = 7union,or,in都能命中索引,建议使用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 改写,单开一文来讲

详解mysql什么时候不走索引相关推荐

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

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

  2. mysql数据库隐式表_详解MySQL数据库常见的索引问题:无索引,隐式转换,附实例说明...

    概述 在这些年的工作之中,由于SQL问题导致的数据库故障层出不穷,而索引问题是SQL问题中出现频率最高的,常见的索引问题包括:无索引,隐式转换. 索引问题 1.无索引 当数据库中出现访问表的SQL无索 ...

  3. mysql影响行数解析_详解MySQL的数据行和行溢出机制

    一.行 有哪些格式? 你可以像下面这样看一下你的mysql行格式设置. 其实mysql的数据行有两种格式,一种就是图中的 compact格式,还有一种是redundant格式. compact是一种紧 ...

  4. mysql临键锁_详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)

    详解 MySql InnoDB 中的三种行锁(记录锁.间隙锁与临键锁) 前言 InnoDB 通过 MVCC 和 NEXT-KEY Locks,解决了在可重复读的事务隔离级别下出现幻读的问题.MVCC  ...

  5. mysql如何查看事务日记_详解 Mysql 事务和Mysql 日志

    事务特性 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节. 2.一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破 ...

  6. mysql 日期比较_详解Mysql中日期比较大小的方法

    假如有个表product有个字段add_time,它的数据类型为datetime,有人可能会这样写sql: 代码如下 select * from product where add_time = '2 ...

  7. 详解Mysql中日期比较大小的方法

    假如有个表product有个字段add_time,它的数据类型为datetime,有人可能会这样写sql: 代码如下 select * from product where add_time = '2 ...

  8. mysql外键约束详解_详解MySQL 外键约束

    详解MySQL 外键约束,西欧,西西里,玛雅,兵种,诺曼 详解MySQL 外键约束 易采站长站,站长之家为您整理了详解MySQL 外键约束的相关内容. 官方文档: https://dev.mysql. ...

  9. mysql分区表truncate分区数据_详解MySQL分区表

    前言: 分区是一种表的设计模式,通俗地讲表分区是将一大表,根据条件分割成若干个小表.但是对于应用程序来讲,分区的表和没有分区的表是一样的.换句话来讲,分区对于应用是透明的,只是数据库对于数据的重新整理 ...

最新文章

  1. spark出现task不能序列化错误的解决方法 org.apache.spark.SparkException: Task not serializable...
  2. 2017 ACM/ICPC(西安)赛后总结
  3. com.alibaba.druid.sql.parser.ParserException: ERRO
  4. Keras TensorFlow教程:如何从零开发一个复杂深度学习模型
  5. Jenkins实现Android自动化打包
  6. python 获取json中最大值_详细解析 Python 爬取 bilibili 的视频、弹幕以及封面
  7. 华为南太无线解决方案部梁旭阳_华为无线充电新专利:激光无线充电,替代传统半接触式...
  8. LeetCode 660. 移除 9(9进制)
  9. ROS在类中发布和接受消息(标准消息)
  10. DBA日常工作职责 - 我对DBA的七点建议
  11. java float存储方式_Java中小数的存储方式
  12. Html的页面演变史02
  13. SICP Python 描述 中文版
  14. Redis持久化——AOF机制详解
  15. java.sql.SQLException: sql injection violation, multi-statement not allow
  16. python 画三角函数_Python计算三角函数之asin()方法的使用
  17. request库的基本用法
  18. 初识高德地图和百度地图
  19. [AHK]为通达信标记文字窗口的按钮增加热键
  20. 这100佳创新互联网公司值得你去

热门文章

  1. [转载] Python列表排序 list.sort方法和内置函数sorted
  2. julia自然常数_Julia中的Sys.KERNEL常数
  3. css div撑满窗口高度_如何使用CSS将div的高度设置为窗口的100%?
  4. Linux中远程文件的传输
  5. c ++向量库_在C ++中对2D向量进行排序
  6. stl min函数_std :: min_element()函数以及C ++ STL中的示例
  7. numpy zeros矩阵_零矩阵使用numpy.zeros()| 使用Python的线性代数
  8. 这个 bug 让我更加理解 Spring 单例了
  9. 厉害了,3万字的MySQL精华总结 + 面试100问!
  10. Java14来了!Switch竟如此简单?Lombok也不需要了?来用Idea搭建Java14吧!