【数据库】聊聊常见的索引优化-下

分页查询优化

主键排序
在这里插入图片描述
在实际的使用中,通过limit 10000,10 查询第10000记录到10010记录,mysql执行的时候是按照将前10010记录全部统计出来,然后剔除前10000条记录,选择后10条记录。这样来看的话,效率不高。

在这里插入图片描述
如果数据是有序的,那么可以直接使用上面这种方式,发现使用了索引,在于这种方式是通过id选择大于10000的数据。两种方式不同。但是如果数据有删除的可能,那么不推荐使用这种方式。并且这种方式需要主键连续才可以。

非主键排序
在这里插入图片描述
但是如果使用 order by name limit,发现没有走索引,具体原因就是mysql优化器发现走索引之后的成本还不如全表查询,放弃了索引。

如何优化呢?

关键点其实就是尽可能使用较少的字段排序。如下只使用主键id排序。指向效率大大高于上面这个。
在这里插入图片描述

Join关联查询优化


-- 示例表:
CREATE TABLE `t1` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `a` int(11) DEFAULT NULL,
 `b` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`),
 KEY `idx_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 create table t2 like t1;
-- 插入一些示例数据
-- 往t1表插入1万行记录
drop procedure if exists insert_t1; delimiter ;;
create procedure insert_t1()
begin
   declare i int;
   set i=1;
   while(i<=10000)do
     insert into t1(a,b) values(i,i);
     set i=i+1;
   end while;
 end;;
 delimiter ;


call insert_t1();
-- 往t2表插入100行记录
drop procedure if exists insert_t2; delimiter ;;
create procedure insert_t2()
begin
  declare i int;
  set i=1;
  while(i<=100)do
    insert into t2(a,b) values(i,i);
    set i=i+1;
  end while;
end;;
delimiter ;
call insert_t2();

上述的SQL 我们创建了两个结构一样的表T1和T2,T1插入1W行数据。T2插入100条记录。

 EXPLAIN select * from t1 inner join t2 on t1.a= t2.a;

那么针对上述的这个SQL,MySQL内部是怎么执行的?
有两种执行算法,决定选择哪个算法取决于关联字段是否有索引。

  • Nested-Loop Join算法 (关联字段有索引)
  • Block Nested-Loop Join算法 (关联字段没有索引)

嵌套循环连接 Nested-Loop Join(NLJ) 算法

嵌套循环执行其实就是每次驱动表拿出一条记录,在这样记录找到关联的字段,根据关联字段在另一张表(驱动表)取出满足条件的行。然后汇总结果。
在这里插入图片描述
从图中可以看出,以下信息

  • 因为id相同,所以T2就是驱动表,T1是被驱动表,小表驱动大表。inner join前的表不一定就是驱动表,mysql会优化。
  • 对于 left join来说,左表是驱动表,右表是被驱动表。right join相反。所以需要合理选择驱动表。
  • 使用了NLJ算法,在join语句中,没有显示Using join buffer,表示使用的join算法是NLJ。

上述的整体流程其实就是
1.T2每次从表中取出一条记录。在和T1中符合条件的数据匹配,将结果存储起来。最后直到执行完毕所有的结果。T2扫描100行。T1扫描100行。一共是200行。

基于块的嵌套循环连接 Block Nested-Loop Join(BNL)算法

本算法其实就是将驱动表T2全部数据拉到内存 join buffer中,然后扫描被驱动表,将被驱动表的每一行都取出来根join_buffer的数据进行对比。 图中显示的是using join buffer说明使用的是BNL算法。
在这里插入图片描述
上述的整体流程
其实就是将T2中的全部100行数据拉到join buffer中,然后把表T1中每一行数据都取出来,进行对比。我们来分析下扫描的行数。T2是100行,T1是1W行,在内存中执行需要 100 * 10000 = 100万次比较。
因为join_buffer_size是有限制的,默认是256K,如果超过这个范围,就是分段放。

思考
为什么对于没有索引的关联字段使用BNL算法,而不是Nested-Loop Join算法呢。
我们来分析,如果采用Nested-Loop Join算法,因为关联的b 字段没有索引,所以也就是T2和T1在次盘层面扫描100 * 10000 = 100W次。这个效率很慢的,相比于BNL算法在内存中比较100W次效率肯定更快。


好了,这里简单总结下,其实对于join的方式,不建议3张表以上的操作,并且对于关联字段要使用索引,选择NLJ算法,而不是BNL算法。小表驱动大表。straight_join 知道哪个是小表,可以使用straight_join进行指定。

 EXPLAIN select * from t1 straight_join t2 on t1.a= t2.a;

straight_join 就制定了一个大表T1。
在这里插入图片描述

 EXPLAIN select * from t2 straight_join t1 on t1.a= t2.a;

执行了T2,明显比上面的性能更好
在这里插入图片描述

  • straight_join只适用于inner join,并不适用于left join,right join。(因为left join,right join已经代表指 定了表的执行顺序)

小表的定义
在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表。

in和exsits优化

in : 表B的数据集小于A表的数据集时,in由于exists

select * from A where id in (select id from B)
#等价于:
for(select id from B){
 select * from A where A.id = B.id 5
}

exists:当A表的数据集小于B表的数据集时,exists优于in

select * from A where exists (select 1 from B where B.id = A.id) 2 #等价于:
 
for(select * from A){
	 select * from B where B.id = A.id
}

#A表与B表的ID字段应建立索引

count(*) 查询优化

 EXPLAIN SELECT count(1) FROM employees;
 EXPLAIN SELECT count(*) FROM employees;
 EXPLAIN SELECT count(name) FROM employees;
 EXPLAIN SELECT count(id) FROM employees;

字段有索引:count( * ) ≈ count(1) > count(字段) >count(主键 id) 字段有索引,count(字段)统计走二级索引,二 级索引存储数据比主键索引少,所以 count(字段)>count(主键 id)

字段无索引:count( * )≈count(1)>count(主键 id)>count(字段) //字段没有索引count(字段)统计走不了索引, count(主键 id)还可以走主键索引,所以count(主键 id)>count(字段)

count(1) : 其实就是把每一行的数据取出来,然后填充1 进行累加。
count(id) : 将每一行的主键id拿出来,累加。
count(*) : 不会将每一行的数据直接取出来,而是做了优化。累加。
coungt(字段):其实统计的是字段不为空的数据。

有什么统计总行数的解决方案?
1.如果存储引擎是MyISAM,会存储在磁盘可以直接获取。但是InnoDB中的MVCC机制,会导致记录的行数不准确,所以没有。
2.show table status

 SHOW TABLE STATUS LIKE 'employees';

3.通过redis或者数据技术表进行统计

阿里MySQL规范

在MySQL中选择正确的数据类型,可以减少磁盘空间,以及对查询性能有一定的提高。
1.确定合适的大类型:数值、字符串、时间、二进制等
2.选择具体的类型:有无符号,取值范围,变长定长等。
尽量把字段定义为not null ,不要null

数值类型

在这里插入图片描述

  • 1.如果整形数据没有负数,如ID号,建议指定为UNSIGNED无符号类型,容量可以扩大一倍。
  • 2.DECIMAL最适合保存准确度要求高,而且用于计算的数据,比如价格。

时间类型

在这里插入图片描述

  • 建议用DATE数据类型来保存日期。MySQL中默认的日期格式是yyyy-mm-dd。
  • 当数据格式为TIMESTAMP和DATETIME时,可以用CURRENT_TIMESTAMP作为默认(MySQL5.6以后), MySQL会自动返回记录插入的确切时间

字符串类型

在这里插入图片描述

  • char 定长字符串、varchar 非定长字符串,
  • 如果存储的字符串长度几乎相等,使用char,比如存储 UUID这种,但是如果不是固定的,那么使用varchar。

小总结

本篇从limit、join 、count 、以及对应的数据类型 介绍了如何优化SQL。结合上一篇。
常见的索引SQL优化就介绍完毕了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】upper_bound和lower_bound

一个是返回第一个大于等于val的element的iter&#xff0c;另一个是返回第一个大于val的element的iter

2024年如何跻身前1%?

2024年如何跻身前1%&#xff1f; 8个习惯助你成为更好的自己 随着2023年即将结束&#xff0c;大家都在为2024年定下目标、列出清单并下定决心。新的一年不仅是结束和告别旧的自己、犯过的错误以及失败的战斗&#xff0c;也是期待着新的开始。 如果你也希望超越困境&#xff…

buuctf-Misc 题目解答分解109-111

109.[CFI-CTF 2018]webLogon capture 流量包分析&#xff0c; wireshark 打开 就这几个数据包&#xff0c;追踪http 进行url 解码 URL网址解码器 - 在线网址解码 得到flag CFI{1ns3cur3_l0g0n} 110.[GKCTF 2021]excel 骚操作 下载 excel 文件 &#xff0c;打开 发现点击其他地…

vue结合Cesium加载gltf模型

Cesium支持什么格式&#xff1f; Cesium支持的格式包括&#xff1a;3D模型格式&#xff08;如COLLADA、gITF、OBJ&#xff09;、影像格式&#xff08;如JPEG、PNG、GeoTIFF&#xff09;、地形格式&#xff08;如STL、Heightmap&#xff09;、矢量数据格式&#xff08;如GeoJSON…

CSS基础笔记-04cascade-specificity-inheritance

CSS基础笔记系列 《CSS基础笔记-01CSS概述》《CSS基础笔记-02动画》CSS基础笔记-03选择器 前言 Cascading Style Sheets&#xff0c;关键就在于这个cascading&#xff0c;对于这个术语理解&#xff0c;感觉对于我这种CSS新手有点儿不太friendly。本文记录下我对这个术语的理…

二叉树的经典算法(算法村第八关青铜挑战)

二叉树里的双指针 所谓的双指针就是定义了两个变量&#xff0c;在二叉树中有需要至少定义两个变量才能解决问题。这两个指针可能针对一棵树&#xff0c;也可能针对两棵树&#xff0c;姑且也称之为“双指针”。这些问题一般与对称、反转和合并等类型题相关。 判断两棵树是否相…

1- forecasting at scale论文阅读

目录 1. 什么是时间序列2. 什么是时间序列预测3. 时间序列预测的范式4. 时间序列的专有名词介绍5. 时间序列评估 1. 什么是时间序列 按时间先后顺序出现的有序序列 2. 什么是时间序列预测 点预测&#xff1a;预测未来的某一个时间点&#xff0c;它的值到底是多少&#xff0c…

高效管理文件方法:每4个文件前面加序号,4个文件后面又单独编号技巧

在日常工作中&#xff0c;文件管理是一项常见的任务。要更高效地管理文件&#xff0c;可以通过在每个文件前面加序号&#xff0c;并在每个序号对应的文件后面进行单独编号的方法来实现。这种方法有助于快速找到所需文件&#xff0c;也能提高工作效率。下面一起来看下云炫文件管…

K8S部署的pod一直处于Pending状态问题解决

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

初识动态内存管理

前言&#xff1a; 我们都知道&#xff0c;内存分为几个区——栈区、堆区、静态区、常量区、代码区&#xff0c;我们在写代码的时候经常会遇到栈溢出这个问题&#xff0c;是因为在程序运行之前&#xff0c;我们无法准确的知道要分配多少空间给程序&#xff0c;所以说很容易造…

监控API的指标

监控服务器已经是常态了&#xff0c;但是监控API的表现是啥意思呢&#xff1f;还有监控指标&#xff1f;今天就来看看如何监控API。 正如监控应用程序以确保高质量性能一样&#xff0c;也必须监控API。 API是应用程序相互通信的管道。更具体地说&#xff0c;API提供了一种方法…

【算法每日一练]-图论(保姆级教程篇14 )#会议(模板题) #医院设置 #虫洞 #无序字母对 #旅行计划 #最优贸易

目录 今日知识点&#xff1a; 求数的重心先dfs出d[1]和cnt[i]&#xff0c;然后从1进行dp求解所有d[i] 两两点配对的建图方式&#xff0c;检查是否有环 无向图欧拉路径路径输出 topodp求以i为终点的游览城市数 建立分层图转化盈利问题成求最长路 会议&#xff08;模板题&a…

向日葵远程工具安装Mysql5.7的安装与配置

文章目录 一、向日葵远程工具安装二、Mysql5.7的安装与配置2.1解压2.2再把my.ini文件放入解压后的文件里面2.3.改变my.ini文件2.4.用管理员身份运行cmd&#xff0c;进入bin文件夹里&#xff0c;运行"mysqld install"命令&#xff0c;出现以下就说明成功了2.5.注册完s…

20. Mysql 游标的定义和使用

文章目录 概念游标的基本语法声明游标打开游标使用游标关闭游标精选示例 总结 概念 游标&#xff08;Cursor&#xff09;是一种数据库对象&#xff0c;可以指向存储在数据库表中的数据行指针。用于在 sql 语句的执行过程中&#xff0c;通过对查询结果集进行逐行的操作和访问。…

【大数据进阶第三阶段之Hive学习笔记】Hive常用命令和属性配置

目录 1、Hive安装 2、HiveJDBC访问 2.1、启动hiveserver2服务 2.2、连接hiveserver2服务 2.3、注意 3、Hive常用交互命令 3.1、“-e”不进入hive的交互窗口执行sql语句 3.2、“-f”执行脚本中sql语句 4、Hive其他命令操作 4.1、退出hive窗口 4.2、在hive cli命令窗口…

rosbag 源码阅读笔记-1

这篇文字想通过在自己的机器上查找rosbag的源码在哪里&#xff08;而不是通过google搜索&#xff09;&#xff0c;来和大家分享一些ros和python的常用命令&#xff0c;了解一下rosbag的调用过程。 怎么查到源码在哪里 当然我们可以直接上ros的官网去查看&#xff0c;路径在这…

静态网页设计——科学家网(HTML+CSS+JavaScript)(dw、sublime Text、webstorm、HBuilder X)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a;https://www.bilibili.com/video/BV1wg4y1Q7qm/?vd_source5f425e0074a7f92921f53ab87712357b 源码&#xff1a;https://space.bilibili.com…

基于Springboot的在线考试系统

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88499371 mysql5、mysql8都可使用 内含配置教程文档&#xff0c;一步一步配置 Springboot所写 管理员页面 学生页面

jetson deepstream 解码接入编码输出

不需要编解码输出画面的直接到7 使用就行 1 jetson主板编译工具 在jetson主板上安装gstreamer工具链&#xff0c;编译opencv sudo apt install -y libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-ugly gstreamer1.0-rtsp python3-dev pytho…

【信息论与编码】习题-判断题-第三部分

目录 判断题48. 利用状态极限稳态分布概率和符号的状态一步转移概率来求m阶马尔可夫信源的极限熵。49. 连续信源或模拟信号的信源编码的理论基础是限失真信源编码定理 。50. 具有一一对应关系的无噪信道的信道容量CH(X)。51. 在游程编码过程中&#xff0c;“0”游程和“1”游程…