首页 > 数据库 >MySQL索引怎么优化

MySQL索引怎么优化

时间:2024-07-01 15:27:09浏览次数:19  
标签:数据 查询 索引 xx MySQL where 优化 select

索引优化无非就是两点:

  • 把SQL的写法进行优化,对于无法应用索引,或导致出现大数据量检索的语句,改为精准匹配的语句。
  • 对于合适的字段上建立索引,确保经常作为查询条件的字段,可以命中索引去检索数据。

连接查询时尽量不关联太多表

关联太多会导致执行效率变慢

多表查询时一定要以大驱小

用小的数据集去驱动大的数据集,就是先查小表,用小表的结果去大表中检索数据,MySQL的优化器有驱动表的优化,执行多表联查MySQL的关联算法为Nest Loop Join,该算法会依照驱动表的结果集作为循环基础数据,然后通过该结果集中一条条数据,作为过滤条件去下一个表中查询数据,最后合并结果得到最终数据集。

  • 指定了连接条件,满足查询条件的小数据表作为驱动表。
  • 未指定连接条件,数据总行数少的表作为驱动表。

通常使用in做子查询时,都要确保in的条件位于所有条件的最后面,这样能够在最大程度上减小多表查询的数据匹配量,在下一道工序开始前尽量缩小数据量,为下一道工序尽可能提供更加精准的数据。

不要使用like左模糊和全模糊查询

like关键字以 % 开头会导致索引失效,千万要避免 %xxx、%xxx% 这两种情况出现。

查询时不要对字段做空值判断

会导致索引失效,想为空的字段,可以设计一个0、" "这类空字符代替,一方面要查询空值时可通过查询空字符的方式走索引检索,同时也能避免MyBatis注入对象属性时触发空指针异常。

不要在条件查询 = 前对字段做任何运算

使用函数也不可以,优化器生成执行计划时,发现 = 前涉及逻辑运算就不会继续往下走了。

!=、!<>、not in、not like、or...要慎用

也可能会导致索引失效,可以使用其他语法代替,比如or使用union all代替。

select user_name from zz_users where user_id=1 or user_id=2;
-- 可以替换成:
select user_name from zz_users where user_id=1
union all
select user_name from zz_users where user_id=2;

必要情况可以强制指定索引

优化器面对复杂 SQL 时没有那么智能,有时选择的索引并不是做好的,对索引结构足够熟悉的情况下,可以通过force index指定索引。

select * from zz_users force index(unite_index) where user_name = "熊猫";

避免频繁创建、销毁临时表

临时表是一种数据缓存,对于一些常用的查询结果可以为其建立临时表,后续要查询时可以直接基于临时表来获取数据,MySQL默认会在内存中开辟一块临时表数据的存放空间,走临时表查询数据是直接基于内存的,速度会比走磁盘检索快上很多倍。注意:只有对于经常查询的数据才对其建立临时表,不要盲目的去无限制创建,否则频繁的创建、销毁会对MySQL造成不小的负担。

尽量将大事务拆分为小事务执行

一个事务在执行时,如果包含了写操作,会先获取锁再执行,直到事务结束后MySQL才会释放锁。一个事务比较大时,导致一部分数据锁定周期长,高并发情况下会有大量事务阻塞,最终拖垮整个MySQL系统。

  • show status like 'innodb_log_waits';查看是否有大事务由于redo_log_buffer不足,而在等待写入日志。

大事务也会导致日志写入时出现阻塞,这种情况下会强制触发刷盘机制,大事务的日志需要阻塞到有足够的空间时,才能继续写入日志到缓冲区,这也可能会引起线上出现阻塞。

从业务设计层面减少大量数据返回的情况

一次性返回的数据量过于巨大时,就会引起网络阻塞、内存占用过高、资源开销过大的各类问题出现,如果项目中存在这类业务,一定要拆分掉,比如分批返回给客户端。每次基于上次返回数据的界限,再一次读取一批数据返回给客户端,也就是经典的分页场景,通过分页的思想能够提升单次查询的速度,以及避免大数据量带来的一系列后患问题。

避免深分页的情况出现

select xx,xx,xx from yyy limit 100000,10; 

查询第1w 页数据,一共查询10w 条数据,然后丢弃前10w 条数据返回最后10条数据。

  • 解决方案:

查询的结果集存在递增且连续的字段,可以基于有序字段做一步筛选在获取分页数据。这种情况会先按where条件筛选数据后,再获取前10条数据返回。也可通过between做优化。

-- 第一页
select xx,xx,xx from yyy where 有序字段 >= 1 limit 10; 
-- 第二页
select xx,xx,xx from yyy where 有序字段 >= 11 limit 10; 
-- 第N页.....

-- 第10000页
select xx,xx,xx from yyy where 有序字段 >= 100001 limit 10; 
-- 舍弃了limit关键字来实现分页,但这种方式仅适合于基于递增且连续字段分页。
select xx,xx,xx from yyy where 有序字段 between 1000000 and 1000010; 

搜素分页的情况下是无序的,数据可以位于表中的任意行,就算存在有序字段也不会连续。就只能通过在业务上限制深分页的情况。以百度为例,显示大约搜索到了一亿条数据,往后拉就会发现,最大只能显示76页,然后会提示“限于网页篇幅,部分结果未予显示”。这种思想仅局限于业务允许的情况下,以搜索为例,一般用户最多看前面30页,如果还未找到他需要的内容,基本上就会换个更精准的关键词重新搜索。

如果业务必须要求展现所有分页数据,此时又不存在递增的连续字段,要么选择之前哪种很慢的分页方式,要么就直接抛弃所有!每次随机十条数据出来给用户,如果不想重复的话,每次新的分页时,再对随机过的数据加个标识即可。

SQL务必写完整,不要使用缩写

这种隐式的写法在MySQL底层会做一次转换,为完整的写法。考虑极致的优化,将SQL写成完整的语法。

-- 为字段取别名的简单写法
select user_name "姓名" from zz_users;
-- 为字段取别名的完整写法
select user_name as "姓名" from zz_users;

-- 内连表查询的简单写法
select * from 表1,表2... where 表1.字段 = 表2.字段 ...; 
-- 内连表查询的完整写法
select * from 表1 别名1 inner join 表2 别名2 on 别名1.字段 = 别名2.字段;

基于联合索引查询时确保字段的顺序性

基于建立的联合索引查询数据,就必须要按照索引字段的顺序去查询数据,否则可能导致不能完全利用联合索引,要遵循索引最左前缀原则。

客户端的一些操作可批量化完成

xxDao.insertBatch(xxObjs);

/**
 * xxDao.insertBatch(xxObjs)对应的SQL如下:
 * insert into tb_xxx values(......),(......),(......),(......),.....;
**/

会组合成一条SQL发送给MySQL执行,能够在很大程度上节省网络资源的开销,提升批量操作的执行效率。同样适用于修改场景,如果一个业务会出现批量修改的情况时,也切记不要用for循环来调用update语句对应的接口,而是应该再写一个update/replace语句的批量修改接口。

明确仅返回一条数据的语句可以使用limit 1

select * from zz_users where user_name = "竹子";
select * from zz_users where user_name = "竹子" limit 1;

后者大多数情况下会比前者好,加上limit 1关键字后,当程序匹配到一条数据时就会停止扫描,不加的情况下会将所有数据都扫描一次。一般情况下,如果确定了只需要查询一条数据,就可以加上limit 1提升性能。

但在一些极端情况下,性能可能相差不大,比如要查询的数据位于表/索引文件的最后面,那么依旧会全部扫描一次。还有一种情况是基于主键/唯一索引字段查询数据时,这些字段值本身具备唯一性,MySQL在执行时,当匹配到第一个值时就会自动停止扫描,因此上述这个方案只适用于普通索引字段、或表中的普通字段。

参考文档

标签:数据,查询,索引,xx,MySQL,where,优化,select
From: https://blog.csdn.net/weixin_46984703/article/details/140102344

相关文章

  • MySQL中的网络命名空间支持
    NetworkNamespaceSupport(网络命名空间支持)提供了在Linux系统中创建和管理多个隔离网络空间的能力。网络命名空间是来自主机系统的网络堆栈的逻辑副本。网络命名空间对于设置容器或虚拟环境非常有用。每个名称空间都有自己的IP地址、网络接口、路由表等等。默认命名空间或全......
  • 升级到 MySQL 8.4,MySQL 启动报错:io_setup() failed with EAGAIN
    问题最近碰到一个case,一台主机上,部署了多个实例。之前使用的是MySQL8.0,启动时没有任何问题。但升级到MySQL8.4后,部分实例在启动时出现了以下错误。[Warning] [MY-012582] [InnoDB] io_setup() failed with EAGAIN. Will make 5 attempts before giving up.[W......
  • mysql数据库简介
    一、数据库介绍1.数据库基本概念数据(Data)描述事物的符号记录包括数字,文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储表将不同的记录组织在一起用来存储具体数据数据库表的集合,是存储数据的仓库以一定的组织方式存储的相互有关的数据集合数据......
  • 知识不成体系?这篇Mysql数据库将成为你的解忧杂货店!(子查询)
     欢迎来到@一夜看尽长安花博客,您的点赞和收藏是我持续发文的动力对于文章中出现的任何错误请大家批评指出,一定及时修改。有任何想要讨论的问题可联系我:[email protected]。发布文章的风格因专栏而异,均自成体系,不足之处请大家指正。   专栏:java全栈C&C++PythonAIP......
  • 1974Springboot医院远程诊断管理系统idea开发mysql数据库web结构java编程计算机网页源
    一、源码特点 springboot医院远程诊断管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSPjava编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。springboot医院远程诊断系统......
  • 基于模型预测控制(MPC)的微电网调度优化的研究(Matlab代码实现)
     ......
  • 【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调
    ......
  • Mysql模拟数据
    模拟SQL模拟报表数据(每日一条记录)--删除现有临时表(如果存在)DROPTEMPORARYTABLEIFEXISTStemp_citypower_dates;--创建临时表用于生成模拟数据CREATETEMPORARYTABLEtemp_citypower_dates(city_idINT,daytimeDATE,typeINT,powerDECIMAL(1......
  • 使用explain优化慢查询的业务场景分析
    问:你最害怕的事情是什么?答:搓澡问:为什么?答:因为有些人一旦错过,就不在了Explain这个词在不同的上下文中有不同的含义。在数据库查询优化的上下文中,"EXPLAIN"是一个常用的SQL命令,用于显示SQL查询的执行计划。执行计划是数据库如何执行查询的一个详细描述,包括它将使用哪......
  • mysql 主从一致性检测与修复
    percona-toolkit下载需要安装的依赖包[centos7]yum-yinstallperl-Digest-MD5perl-DBIperl-DBD-MySQL--nogpgcheck--disablerepomysql80-community--enablerepomysql57-community原理将一张大表分成多个chunk,每次针对一个chunk进行校验,同时将校验的结果通过REPL......