第21章:索引优化与查询优化

news2024/11/16 11:56:17

一、索引优化与查询优化

1.什么情况下要进行数据库调优

①索引失效,没有充分利用到索引---索引建立

②关联查询太多join---SQL优化

③服务器调优和各个参数的设置---调整my.cnf

④数据过多---分库分表

2.SQL优化的技术

①物理查询优化:通过索引和表连接方式进行优化

②逻辑查询优化:通过SQL的等价变化提升查询效率

二、关联查询优化

1.左外连接

EXPLAIN SELECT SQL_NO_CACHE * FROM `type` LEFT JOIN book ON type.card = book.card;

驱动表(左表A):type

被驱动表(右表B):book

①没有索引

 type的值是all,进行的全表扫描,效率低。

②给被驱动表book添加索引

alter table book add index Y (card);
或
create index Y on book(card);

 发现book的type为ref,类型表示 MySQL 在查询时使用了非唯一索引,通常是在连接操作中使用。避免全表扫描效率高。

给驱动表type添加索引,删除book的索引Y

create index X on type(card);
drop index Y on book;

【左外连接优化分析】

左外连接在查询时,左表的每一条数据跟右表的数据进行挨个匹配,左表建立索引意义不大。

左连接时对右表on的字段建立索引,提高查询效率。

 2.内连接

EXPLAIN SELECT SQL_NO_CACHE * FROM `type` INNER JOIN book ON type.card = book.card;

 

①添加book索引

create index Y on book(card);

 发现book的type为ref,类型表示 MySQL 在查询时使用了非唯一索引,通常是在连接操作中使用。避免全表扫描效率高。

②添加type索引

create index X on type(card);

 ③删除book索引

【内连接优化分析】

在内连接中,如果此时有一个表的连接条件中的字段有索引,那么这个表会作为被驱动表。

如果两个表的连接字段都有索引。数据量小的是驱动表,数据量大的是被驱动表。小表驱动大表

所以给数据量大的表创建索引就能提高查询效率

三、JOIN语句原理

1.判断驱动表和非驱动表

①左外连接:左边是驱动表,右边是被驱动表

②右外连接:右边是驱动表,左边是被驱动表

③内连接inner order:mysql会选择数据量小的是驱动表,数据量大的是非驱动表

④通过EXPLAIN查看SQL的执行计划,第一行的表是驱动表

2.join语句的相关算法

①Simple Nested-Loop Join简单嵌套循环连接SNLJ

从表A取出1条数据,遍历表B。匹配结束清除内存,然后再加载A的1条数据,进行匹配。效率低。

②Index Nested-Loop Join索引嵌套循环连接INLJ

主要思想是减少内层数据的匹配次数,所以是让被驱动表必须有索引才行。效率高

③Block Nested-Loop Join 块嵌套循环连接BNLJ(MySQL8.0取消了)

如果没有索引,将驱动表join相关部分的列缓存到join buffer中,然后全表扫描被驱动表。被驱动表的记录和块记录进行匹配。跟一条一条记录比较来说能减少IO的次数。

 

【小结】

①整体的效率比较:INLJ>BNLJ>SNLJ

②小表驱动大表,本质减少外层循环的数据数量。为被驱动表匹配的条件增加索引,减少内层循环数量。

③增大join buffer size的大小,一次性缓存的数据多,扫表的次数越少。减少驱动表不必要的查询字段,join buffer缓存的数据越多

四、排序优化order by

1.在where条件字段上加索引,但是为什么在order by 字段还要添加索引?

①在where子句添加索引是避免全表扫描,在order by子句添加索引是避免使用FileSort排序(占CPU,效率低)。

②尽量使用索引完成order by排序。如果where和order by后面相同的列使用单列索引。如果不同使用联合索引。

③无法使用索引时,需要对FileSort方式调优

2.排序时使用索引的情况

创建索引:index a_b_c(a,b,c)

①order by使用索引最前缀

order by a

order by a,b

order by a,b,c

order by a desc,b desc,c desc

②where 使用的索引最左前缀为常量,order by能使用索引

where a = 常量 order by b,c

where a = 常量 and b = 常量 order by c

where a = 常量 and b > 常量 order by b,c

③不能使用索引

order by a asc,b desc,c desc 排序不一致

where g = 常量 order by b,c 丢失a索引

where a = 常量 order by c 丢失b索引

where a = 常量 order by a,d d不是索引

WHERE a in (...) ORDER BY b,c 对于排序来说,多个相等条件也是范围查询

3.案例实战

order by子句尽量使用索引方式排序,避免使用filesort排序

场景:查询年龄是30岁,且学生编号小于101000学生,按照用户名称排序

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 30 AND stuno <101000 ORDER BY  NAME ;

 type是all,进行全表扫描最坏的情况。Extra出现了Using filesort。要进行优化

①方案一:创建索引age_name,没有使用filesort

CREATE INDEX idx_age_name ON student(age,NAME);

②方案二:where和order by 字段使用索引,使用filesort

CREATE INDEX idx_age_stuno_name ON student (age,stuno,NAME);

速度快

五、分组优化group by

1.group by 使用原则跟order by一致,没有where过滤条件也可以直接用索引。

2.group by先排序再分组,遵循索引建立的最佳左前缀原则

3.where效率高于having,能写在where条件里就不写在having中

4.减少使用order by,group by,distinct语句费CPU。

5. 用order by,group by,distinct语句,where条件过滤出的结果在1000行以内,否则SQL很慢。

六、优化分页查询

分页语句:

查询排序的代价非常大

select * from student limit 2000000,10;

优化思路一:

适用于主键自增的表,把limit查询通过where过滤条件,转换成某个位置的查询

select * from student where id > 2000000 limit 10;

优化思路二:

在索引上完成排序分页操作查询出主键,最后根据主键关联回原表查询所需内容。

select * from student t,(select id from student order by id limit 2000000,10) a

where t.id=a.id;

七、覆盖索引的使用

1.什么是覆盖索引

①覆盖索引是一种数据查询方式,不是索引的类型。索引列+主键包括在select到from中

②通过索引值可以直接找到查询字段的值,不需要回表操作就是覆盖索引

如: CREATE INDEX idx_name_age ON user(name,age);

查询张三的年龄:

select name, age from user where name = 'zhangsan';

查询的字段name和age都在联合索引idx_name_age的索引树中,这样查询就是覆盖索引查询。

2.覆盖索引的利弊

好处:

①避免Innodb表进行二次查询,不需要回表

②可以把随机IO(回表)变成顺序IO加快查询效率

坏处:

索引字段的维护需要代价。

九、索引条件下推ICP

1.什么是索引条件下推ICP

在非聚簇索引中,判断部分能否使用索引中的列来检查,进行一下过滤,再进行回表操作。这样能减少回表查询次数,提高查询效率

2.案例分析

创建索引

CREATE INDEX idx_name_age ON tuser(name,age);

进行查询:只使用name索引,age失效

SELECT * FROM tuser

WHERE NAME LIKE '张%'

AND age = 10

AND ismale = 1;

没有索引条件下推

storage层:只将满足index key条件的索引记录对应的整行记录取出,返回给server层

server 层:对返回的数据,使用后面的where条件过滤,直至返回最后一行。

使用索引条件下推

storage层:

首先将index key条件满足的索引记录区间确定,然后在索引上使用index filter进行过滤。将满足的index filter条件的索引记录才去回表取出整行记录返回server层。不满足index filter条件的索引记录丢弃,不回表、也不会返回server层。

server 层:

对返回的数据,使用table filter条件做最后的过滤。

3.ICP使用条件

①只能用于二级索引

②表访问的类型是range(范围),ref(条件), ref_or_null(条件和空)

③ICP可以用于MyISAM和InnnoDB存储引擎

④InnnoDB存储引擎,ICP用于二级索引。ICP目标减少全行的读取次数,减少I/O操作。

九、其他查询优化策略

1.exists和in的区分

原则:小表驱动大表

①select * from A where id in (select id from B);

底层执行循环时先B后A,所以B小,A大用in

②select * from A where exists (select id from B where B.id=A.id);

底层执行循环时先A后B,所以A小,B大用exists

2.count(*)和count(具体字段)和count(1)的效率

①count(*)和count(1)本质上没区别

②在MyISAM存储引擎存储了表的行数,查询表的行数是O(1)复杂度。

如果是InnoDB存储引擎,需要全表扫描,复杂度O(n)。

③在InnoDB引擎下,count(具体字段)统计行数尽量不使用主键(信息多),使用非聚簇索引(信息小)。count(*)和count(1)会自动选择效率高的二级索引。

3.为什么不要用select(*),推荐select<字段列表>

①select(*)在MySQL解析中,会通过查询数据字典将*转换为所有列名,消耗时间,降低效率

②select(*)无法使用覆盖索引

4.limit 1对优化的影响

①如果是全表扫描且确定结果集是1,那么加上limit 1时找到一条结果就不继续扫描了,加快查询速度。

②如果对字段建立唯一索引,不会全表扫描,不需要加limit 1

5.多使用commit,为什么会提高性能

commit释放资源:

①回滚段上用于恢复数据的信息

②被程序语句获得锁

③redo / undo log buffer 中的空间

④管理上述 3 种资源中的内部花费

十、淘宝数据库的主键设计

1.自动ID出现的问题

①不可靠

存在自增id回溯的问题,MySQL8.0才修复

②不安全

对外暴露的接口可以才到对应的信息。/user/1接口,猜到用户ID的值多少,用户数量多少

③性能差

自增id由数据库服务端生成,性能差

④交互多

查询刚才插入的id,需要last_insert_id()函数。多1条SQL多一次性能开销。

⑤局部唯一性

当前数据库唯一。不是全局唯一。

2.业务字段做主键出现的问题

①选择卡号

虽然卡号是唯一的,但是卡号会重复使用。比如100001的张三退卡了,商家会把这个卡号给新用户。但是在业务层面会出现问题,如果交易表有会员卡号的字段,有王五购买的信息。此时新用户的交易记录会出现王五的交易流水信息。不能把卡号当主键

②电话或身份证

都属于用户的隐私。

原则:不用业务有关的字段作为主键。否则更改主键的成本非常高

3.淘宝主键的设计

订单ID = 时间 + 去重字段 + 用户ID后6位尾号

这样设计能做到全局唯一,对分布式友好

4.推荐的主键设计UUID

非核心业务:主键自增id,告警,日志,监控等信息

核心业务:全局唯一且单调自增

①UUID的特点

全局唯一,但是无序的(因为时间地位在前面,时间高位在后面),插入性能差

②对UUID进行改造

通过MySQL8.0提供的函数uuid_to_bin(UUID(),true);将UUID转换为有序的。全局唯一+单调递增。

 

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

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

相关文章

图论算法:DFS求有向图或无向图两点间所有路径及Dijkstra算法求最短路径

1、目的 1)根据有向图获取指定起终点的所有路径; 2)直接求解两点间最短路径。 2、示例效果 2.1 原始数据 路线起终点整理如下: // 共计12个顶点,19条边。 (起点,终点,1)最后的1代表起点终点是连通的。 起点,终点,1:2 4 1 起点,终点,1:9 10 1 起点,终点,1:…

Java面向对象程序开发——网络编程入门知识

​ 文章目录 软件结构网络通信协议协议分类网络编程三要素TCP通信程序概述Socket类构造方法成员方法 ServerSocket类构造方法成员方法 简单的TCP网络程序客户端向服务器发送数据服务器端 文件上传服务端实现&#xff1a;客户端实现&#xff1a; BIO 、 NIO 与 AIO 软件结构 C…

Unity3D如何在一个项目建多个场景

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 设置多个场景 您可以添加多个场景、编辑查看场景的方式以及更改场景设置。 要创建新场景&#xff0c;请参阅创建、加载和保存场景。 添加场景 有两种方法可以向项目添加新场景&…

react—路由

1. 注册路由 路由的注册和vue框架中类似&#xff0c;注册过后需要在地址栏输入你想要进去的页面。 // 引入 import { createRoot } from "react-dom/client"; import { createBrowserRouter,RouterProvider,Route,Link }from "react-router-dom"; // 引入…

springboot分组校验

1、分组校验场景 主要2个场景&#xff0c;场景1&#xff1a;多个接口使用相同的入参&#xff0c;不同接口需要校验的内容不同。场景2&#xff1a;针对同一个接口&#xff0c;某个值&#xff08;一般是类型&#xff09;的不同会影响其他值的内容&#xff0c;此时需要根据某个值的…

【Linux】设置 命令 --help 帮助文件为中文

&#x1f341;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; 文章目录 前言设置系统默认语言为中文安装man-…

【C#】并行编程实战:使用 PLINQ(2)

PLINQ 是语言集成查询&#xff08;Language Integrate Query , LINQ&#xff09;的并行实现&#xff08;P 表示并行&#xff09;。本章将继续介绍其编程的各个方面以及与之相关的一些优缺点。 本文的主要内容为 PLINQ 中的合并选项以及抛出和处理异常。 本教程对应学习工程&…

Xshell连接不上虚拟机的解决办法(给他最后一次机会)

VM还原默认设置 如果你之前的操作都没问题的话Xshell还是连接不上我们的虚拟机&#xff0c;可以试试这个方法 点VM中的 编辑–>虚拟网络编辑器–还原默认设置**(这个方法也特别有效)** 注意还原好以后我们主要看一下VM8的 这是没还原之前的NAT设置 没还原之前的DHCP设置…

如何在Windows 10中创建引导到UEFI固件设置的快捷方式

大多数计算机都有一个特定的键,当计算机启动时按下该键,用户可以访问UEFI(固件)设置。然而,我们经常在错过给定的时间段时按键太晚,因为笔记本电脑默认情况下只需等待几秒钟就可以启动到 Windows。 另一个引导到 UEFI 设置的选项是重新启动到高级启动选项,然后从那里开…

centos6.X防火墙110.42.2

防火墙机制介绍122.228.84 Centos5.X 6.X的防火墙机制为什么称为iptables呢&#xff1f; 因为这个防火墙软件里面有多个表格&#xff08;table&#xff09;,每个表格都定义自己的默认策略与规则&#xff0c;且每个表用途都不同。 Centos5.X 6.X 主要表格&#xff08;table&am…

第三课:设计小技巧

前期准备 下载一份官方规范&#xff0c;将官方规范文件置入到 Figma 中&#xff0c;若是使用网页版&#xff0c;建议打开两个 Figma 网页&#xff0c;在两个网页中分别打开规范文档和需要设计的项目&#xff0c;这样便可以通过 Tab 切换&#xff0c;快速将官方文档中的文件复…

学习c++ Part03

文章目录 前言1.动态空间申请1.1 静态空间申请1.2 动态分配 2.字符串处理函数3.结构体3.1 结构体的浅拷贝3.2 结构体的深拷贝3.3 结构体变量在堆区 结构体指针成员也指向堆区&#xff08;先释放成员&#xff0c;再释放结构体&#xff09;3.4 结构体的对齐规则3.5 结构体的位域&…

跟我一起从零开始学python(三)多线程/多进程/协程

前言 回顾之前讲了python语法编程 &#xff0c;关于从零入门python的第一遍&#xff0c;编程语法必修内容&#xff0c;比如python3基础入门&#xff0c;列表与元组&#xff0c;字符串&#xff0c;字典&#xff0c;条件丶循环和其他语句丶函数丶面向对象丶异常和文件处理和网络…

oracle,update更新时,条件没走索引

update更新时没走索引&#xff0c; 查询索引是有效的&#xff1a; 没走索引的原因是条件字段的字段类型不一致&#xff0c; 一个是varchar2&#xff0c; 另一个是 nvarchar2 。 要走索引需要字段类型一致&#xff0c;可以利用to_char()将 nvarchar2转为 varchar2

VS2019+Qt5.15 在线显示百度地图

1.Qt5.15编译程序需要选择mscv2019 Release版本 2.需要到百度地图开发平台注册并获取到开发者key 3.显示地图是JS与Qt的交互过程&#xff0c;显示地图的html文件&#xff1a; <!DOCTYPE html> <html><head> <meta name"viewport" content&q…

订单自动取消的11种实现方式(上)

一、DelayQueue DelayQueue是JDK提供的api&#xff0c;是一个延迟队列 DelayQueue泛型参数得实现Delayed接口&#xff0c;Delayed继承了Comparable接口。 getDelay方法返回这个任务还剩多久时间可以执行&#xff0c;小于0的时候说明可以这个延迟任务到了执行的时间了。 com…

企业微信小程序登录,错误码:60020

在使用企业微信wx.qy.login API进行登录获取【session_key】时&#xff0c;报出错误码&#xff1a;60020 此错误记得好像意指的是获取的企业【access_token】用以去置换登录令牌【session_key】时&#xff0c;下发【access_token】的IP地址和获取【session_key】的IP不一致&am…

kotlin Flow系列之 - 冷流SafeFlow源码解析之 - Safe在那里?

本文涉及源码基于kotlinx-coroutines-core-jvm:1.7.1 kotlin 协成系列文章: 你真的了解kotlin中协程的suspendCoroutine原理吗? Kotlin Channel系列&#xff08;一&#xff09;之读懂Channel每一行源码 kotlin Flow系列之-冷流SafeFlow源码解析之 - Safe在那里&#xff1f; ko…

【vue2动画效果】实现两组单词逐渐减短,最后只保留首字母的效果

前言 实现两组单词逐渐减短&#xff0c;最后只保留首字母的效果 效果&#xff1a; 正文 <template><div class"header"><div style"margin-right: 12px; display: inline-flex"><divclass"door"id"book1"v-f…

常用数据回归建模算法总结记录

本文的主要目的是总结记录日常学习工作中常用到的一些数据回归拟合算法&#xff0c;对其原理简单总结记录&#xff0c;同时分析对应的优缺点&#xff0c;以后需要的时候可以直接翻看&#xff0c;避免每次都要查询浪费时间&#xff0c;欢迎补充。 (1)线性回归 (Linear Regressio…