User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   SQL   ›   MySQL   ›   正文
MySQL

MySQL—理解索引 (3)

2022-02-16 12:03:13
528  0 0
参考目录 隐藏
1) 常见优化方法
2) 联合索引最左前缀原则
3) 不要在列上使用函数和进行运算
4) 负向条件查询不能使用索引
5) 使用覆盖索引
6) 避免强制类型转换
7) 范围列可以用到索引
8) 更新频繁、数据区分度不高的字段上不宜建立索引
9) 索引列不允许为null
10) 避免使用or来连接条件
11) 模糊查询
12) 优化案例
13) 利用延迟关联或者子查询优化超多分页场景
14) 如果明确知道只有一条结果返回,limit 1 能够提高效率
15) 如何建立索引
16) 多值匹配和范围匹配
17) 联合索引的最左匹配原则
18) 根据区分度创建索引
19) 排序字段索引

阅读完需:约 7 分钟

常见优化方法

联合索引最左前缀原则

复合索引遵守「最左前缀」原则,查询条件中,使用了复合索引前面的字段,索引才会被使用,如果不是按照索引的最左列开始查找,则无法使用索引。

比如在(a,b,c)三个字段上建立联合索引,那么它能够加快a|(a,b)|(a,b,c)三组查询的速度,而不能加快b|(b,a)这种查询顺序。

另外,建联合索引的时候,区分度最高的字段在最左边。

不要在列上使用函数和进行运算

不要在列上使用函数,这将导致索引失效而进行全表扫描。

例如下面的 SQL 语句:

select * from artile where YEAR(create_time) <= '2018'; 

即使 date 上建立了索引,也会全表扫描,可以把计算放到业务层,这样做不仅可以节省数据库的 CPU,还可以起到查询缓存优化效果。

负向条件查询不能使用索引

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

select * from artile where status != 1 and status != 2;

可以使用in进行优化:

select * from artile where status in (0,3)

使用覆盖索引

所谓覆盖索引,是指被查询的列,数据能从索引中取得,而不用通过行定位符再到数据表上获取,能够极大的提高性能。

可以定义一个让索引包含的额外的列,即使这个列对于索引而言是无用的。

避免强制类型转换

当查询条件左右两侧类型不匹配的时候会发生强制转换,强制转换可能导致索引失效而进行全表扫描。

如果phone字段是varchar类型,则下面的SQL不能命中索引:

select * from user where phone=12345678901;

可以优化为:

select * from user where phone='12345678901';

范围列可以用到索引

范围条件有:<、<=、>、>=、between等。

范围列可以用到索引,但是范围列后面的列无法用到索引,索引最多用于一个范围列,如果查询条件中有两个范围列则无法全用到索引。

更新频繁、数据区分度不高的字段上不宜建立索引

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

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

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

索引列不允许为null

单列索引不存null值,复合索引不存全为null的值,如果列允许为 null,可能会得到不符合预期的结果集。

避免使用or来连接条件

应该尽量避免在 where 子句中使用 or 来连接条件,因为这会导致索引失效而进行全表扫描,虽然新版的MySQL能够命中索引,但查询优化耗费的 CPU比in多。

模糊查询

前导模糊查询不能使用索引,非前导查询可以。

优化案例

利用延迟关联或者子查询优化超多分页场景

MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行。

当 offset 特别大的时候,效率非常低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。

可以先快速定位需要获取的id段,然后再关联:

selecta.* from 表1 a,(select id from 表1 where 条件 limit 1000000 ,10 ) b where a.id=b.id  

如果明确知道只有一条结果返回,limit 1 能够提高效率

虽然自己知道只有一条结果,但数据库并不知道,明确告诉它,让它主动停止游标移动。

如何建立索引

where a=1 and b=1  
where b=1  
where b=1 order by time desc

建议建立两个索引,即 idx_ab(a,b) 和 idx_b_time(b,time)

MySQL 的查询优化器会自动调整where子句的条件顺序以使用适合的索引,对于上面的第一条 SQL,如果建立索引为idx_ba(b,a) 也是可以用到索引的。

多值匹配和范围匹配

假如有联合索引(empno、title、fromdate),下面的 SQL 是否可以用到索引,如果可以的话,会使用几个?

select * from employee.titles  
where emp_no between '10001' and'10010'  
and title='软件工程师'   
and from_date between '2008-01-01'and '2018-01-01'  

可以使用索引,可以用到索引全部三个列,这个 SQL看起来是用了两个范围查询,但作用于empno上的between实际上相当于in,也就是说empno 实际是多值精确匹配。

在 MySQL 中要谨慎地区分多值匹配和范围匹配,否则会对 MySQL 的行为产生困惑。

联合索引的最左匹配原则

假如建立联合索引(a,b,c),下列语句是否可以使用索引,如果可以,使用了那几列?

where a= 3  // 是,使用了a列
where a= 3 and b = 5  // 是,使用了ab列  
where a = 3 and c = 4 and b = 5  // 是,使用了 a,b,c 列  
where b= 3 // 否
where a= 3 and c = 4  // 是,使用了a列  
where a = 3 and b > 10 and c = 7  // 是,使用了 a,b 列  
where a = 3 and b like 'xx%' andc = 7  // 是,使用了 a,b 列

根据区分度创建索引

有如下查询语句,查找指定产品已审核(status=1)的评论:

SELECT user_id,title,content FROM `comment`
WHERE status=1 AND product_id=1
LIMIT 0,5 ;

可以建立联合索引,status和product_id,但是哪个放左边就要计算区分度:

SELECT COUNT(DISTINCT status)/COUNT(*) AS audit_rate,
COUNT(DISTINCT product_id)/COUNT(*) AS product_rate
FROM comment;

一般product的区分度会高点,可以创建如下索引:

CREATE INDEX idx_productID_Status ON comment(product_id,status)

排序字段索引

查看某个用户最近20条登录记录,按时间排序:

select *  from login_history where uid = $uid order by create_time desc limit 20;

建立uid+timeline复合索引,将排序引入到索引结构中,数据库负载骤降。

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594286浏览

随机文章
RESTful风格
5年前
SpringCloud—GateWay(六)初始化加载流程
5年前
Java—数据库连接池
3年前
Docker—镜像(三)
5年前
SpringCloud—的负载均衡策略
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594286 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付