【MySQL】索引优化与关联查询优化

数据库调优的几个维度:

  • 索引失效,没有充分用到索引——索引建立
  • 关联查询太多JOIN——SQL优化
  • 服务器调优以及各个参数设置——调整my.cnf
  • 数据过多——分库分表

SQL查询优化的几种方式:

  • 物理查询优化:通过索引以及表连接方式进行优化
  • 逻辑查询优化:通过SQL等价变换提升查询效率

一、索引失效案例

1.1、尽量全值匹配

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4 AND NAME='abcd'

CREATE INDEX idx_age ON student(age);                 //执行时间0.149s
CREATE INDEX idx_age ON student(age, classId);        //执行时间0.001s
CREATE INDEX idx_age ON student(age, classId, NAME);  //执行时间0.002s

使用了越多的属性来建立索引,会加快SQL查询的效率,能加速每一个属性的查询

1.2、最佳左前缀法则

CREATE INDEX idx_age ON student(age, classId, NAME);

SELECT  SQL_NO_CACHE * FROM student
WHERE student.age=30 AND student.classId=2 AND NAME='abcd';

在过滤条件(WHERE)中使用了索引的情况下,要按照索引建立时的顺序从左往右筛选,如果中间跳过了某个字段,比如跳过了student.classId,则NAME字段将无法被用来查询

1.3、主键插入顺序

  对于一个使用InnoDB存储引擎的数据库来说,其记录是按照主键值从小到大排序的。如果我们插入的数据是依次递增的,每插满一个数据页就换到下一个数据页继续插。但是插入的数据忽大忽小时,会带来更多得页面分裂以及记录移位。这也就导致了性能损耗。
  所以,可以通过设置主键具有AUTO_INCREMENT,让存储引擎自己为记录生成递增的主键,避免用户手动插入。

1.4、计算、函数、类型转换(自动或者手动)导致索引失效

MySQL中的 类型的值会先作用于函数、计算或者类型转换,再作用于整体的操作

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE LEFT(student.name, 3)='abc';
//这条语句MySQL会将name字段的值一个个取出来进行函数操作后再与abc进行比较,所以用不上索引
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE student.name LIKE 'abc%';
//而这条语句可以用上索引

1.5、范围条件右边的列索引失效

CREATE INDEX idx_age_classId_name ON student(age, classId, NAME);

EXPLAIN SELECT SQL_NO_CACHE * FROM student 
WHERE student.age=10 AND student.classId>20 AND student.NAME='abc';

  如果对索引的过滤条件中限制了一定范围,那么使用B+数来查询后,索引中剩下字段也就没有意义来。这里由于classId在索引的中间位置,所以在它之后的NAME字段索引失效。
  解决失效的方法为重新设置索引

CREATE INDEX idx_age_name_classId ON student(age, NAME, classId);

1.6 不等号索引失效

  使用!=或者<>导致索引失效,原理同上

1.7、is not null 无法使用索引

  is null可以使用索引,is not null无法使用索引,情况类似于等于号可以使用索引,不等号不能使用索引
  解决这类索引失效问题的方法为:将字段设置为NOT NULL约束,可以设置0为INT类型字段的初始值,空字符串为字符串类型的初始值。

1.8、like以通配符%开头索引失效

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE NAME LIKE '%ab'

  开头不确定,所以无法在B+树中搜索

1.9、OR前后存在非索引的列,索引失效

CREATE INDEX student ON student(age)

EXPLAIN SELECT SQL_NO_CACHE * FROM student 
WHERE age=10 OR classId=1

  虽然age可以使用索引,但是classId仍然需要全表扫描,所以整个语句仍然是全表扫描。

1.10、数据库和表的字符集使用不统一

  统一字符集可以避免由于字符集转换产生的乱码,不同字符集进行比较前会进行类型转换导致索引失效。

二、关联查询优化

2.1、左外连接

  在没有索引的情况下进行查询

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

  这种情况相当于把type.card值与book.card值一个一个进行比较。
  对被驱动表book.card添加索引后

CREATE INDEX Y ON book(card);
EXPLAIN SELECT SQL_NO_CACHE * FROM `type` LEFT JOIN book ON type.card = book.card;

  这里相当于驱动表type是一个一个的取,而被驱动表book则是在B+树上进行快速查找

2.2、内连接

  在内连接中小表驱动大表,优化器会对两个表进行计算,将数据量小的表作为驱动表,数据量大的表作为被驱动表。

CREATE INDEX X ON book(card);
EXPLAIN SELECT SQL_NO_CACHE * FROM book INNER JOIN `type` ON book.card = `type`.card; 

  在上面这个语句中,虽然book表在等号左边,但是只有book表具有索引,因此,这里的被驱动表仍然是book表

2.3、JOIN语句原理

  JOIN方式连接多个表,本质上就是各个表之间数据的循环匹配

  • 简单嵌套循环连接(Simple Nested-Loop Join)
      这种方式的效率最低,其算法为将驱动表A中的每一条记录都与被驱动表B进行匹配。
    在这里插入图片描述
  • 索引嵌套循环连接(Index Nested-Loop Join)
      索引嵌套循环连接的优化思路主要是使用索引来替换全表查找来进行优化,从而减小内表的查询次数。
    在这里插入图片描述
  • 块嵌套循环连接(Block Nested-Loop Join)
      为了减少被驱动表的IO次数,出现了块嵌套循环连接的方式,引入了Join buffer 缓冲区,将驱动表的部分数据缓冲到buffer中,然后全表扫描被驱动表进行匹配,将简单嵌套循环中的多次合并为一次,降低了被驱动表的访问频率。

在这里插入图片描述

  • Hash Join
      Hash Join是做大数据集连接时的常用方式,优化器使用较小的表利用Join Key在内存中建立散列表,扫描较大的表并探测散列表进行搜索。

总结

  • 对于JOIN的内部实现来说,整体效率比较INLJ > BNLJ > SNLJ
  • 永远用小结果集驱动大结果集(结果集大小的判断为表行数*每行大小
  • 在INLJ中,为被驱动表匹配的条件增加索引,能够减少内层表的循环匹配次数
  • 在BNLJ中,增大Join buffer size,可以在内存中存下更多得行数,减少内层表的扫描次数
  • 在BNLJ中,减少不必要的字段查询。

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

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

相关文章

微服务分布式中为什么要分库分表呢?

什么是分库分表&#xff1f; 概念&#xff1a; 分库分表是一种数据库水平扩展的方法&#xff0c;通过将数据分散存储在多个数据库实例或多张表中&#xff0c;以提高系统的性能和扩展性。在Java应用中&#xff0c;可以使用一些数据库中间件或框架来实现分库分表。 为什么要分…

2024-3-6-数据库作业

作业&#xff1a;数据库操作的增、删、改完成 源代码&#xff1a; #include <myhead.h> void do_add(sqlite3 *ppDb) {char *errmsg NULL;char sql[128] "insert into Worker values(1001,小张,15000);";// "insert into Worker values(1002,小刘,900…

实验一 将调试集成到vscode

先唤起终端&#xff0c;按照上一篇文章的步骤分别启动调试服务器和调试客户端&#xff0c;然后挂在后台 PS&#xff1a;同时挂两个终端可以开两个窗口&#xff0c;也可以使用多窗口分屏式终端terminator 注意是要图二的光标一直闪&#xff0c;如果熄灭了说明连接超时了&#xf…

Linux中systemv共享内存

目录 1.原理 2.接口 1.shmget(share_memory_get获得共享内存) 2.ftok 3.shmat(share_memory_attaintion挂接到物理内存上) 4.key和shmid的区别 5.ipc 指令 6.shmdt函数&#xff08;share_memory_detach取消挂接&#xff09; 7.shmctl函数&#xff08;share_memory_cont…

【你也能从零基础学会网站开发】Web建站之HTML+CSS入门篇 网站开发的基本概念与站点文件的管理

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1f44d;&…

笔记本上使用usb蓝牙适配器

注意 必须先禁用笔记本上原来的蓝牙功能 禁用笔记本原来的蓝牙功能 使用usb蓝牙适配器

matlab读取hdf5格式的全球火灾排放数据库Global Fire Emissions Database(GFED)数据

1.引言 火灾是大气中痕量气体和气溶胶的重要来源&#xff0c;并且是全球尺度上最重要的干扰因素。此外&#xff0c;森林砍伐和热带泥炭地火灾以及火灾频率增加的地区&#xff0c;都会增加大气中二氧化碳的积累。烧毁面积提供了生物质燃烧事件期间受火灾影响土地的估算&#xff…

实时智能应答数字人搭建

语音驱动口型的算法 先看效果&#xff1a; 你很快就可以帮得上我了 FACEGOOD 决定将语音驱动口型的算法技术正式开源&#xff0c;这是 AI 虚拟数字人的核心算法&#xff0c;技术开源后将大程度降低 AI 数字人的开发门槛。FACEGOOD是一家国际领先的3D基础软件开发商&#xff0c;…

分类算法(Classification algorithms)

逻辑回归(logical regression&#xff09;&#xff1a; 逻辑回归这个名字听上去好像应该是回归算法的&#xff0c;但其实这个名字只是在历史上取名有点区别&#xff0c;但实际上它是一个完全属于是分类算法的。 我们为什么要学习它呢&#xff1f;在用我们的线性回归时会遇到一…

Xss-labs-master 1-16关

第一关 <?php ini_set("display_errors", 0); $str $_GET["name"]; echo "<h2 aligncenter>欢迎用户".$str."</h2>"; ?> <center><img srclevel1.png></center> <?php echo "&l…

OpenAI-Sora学习手册

通过Sora看2024红利&#xff1a;文生视频&#xff0c;虽然AI不一定是风口&#xff0c;但一定是未来深入到生活工作&#xff0c;乃至思考的必备工具。 目录 Sora介绍 Sora基础介绍 Sora官方网址 Sora的价值 1.物理世界的交互 2.创意世界的绽放 3.多角色、更精准、更细节…

两天学会微服务网关Gateway-Gateway网关限流

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…

shell脚本一键部署docker

Docker介绍 Docker 是一个开源的平台&#xff0c;用于开发、交付和运行应用程序。它利用容器化技术&#xff0c;可以帮助开发人员更轻松地打包应用程序及其依赖项&#xff0c;并将其部署到任何环境中&#xff0c;无论是开发工作站、数据中心还是云中。以下是 Docker 的一些关键…

ChatGPT提问技巧——控制温度和TOP-P样本

ChatGPT提问技巧——控制温度和TOP-P样本 “控制温度和Top-P抽样”在自然语言处理中&#xff0c;控制温度是指通过调整生成文本的随机性和多样性&#xff0c;而Top-P抽样是一种生成文本的策略&#xff0c;它选择概率最高的前P个词作为候选词汇。这两个技术常用于生成文本的质量…

ChatGPT在地学、GIS、气象、农业、生态、环境等领域中的应用

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

DataFunSummit 2023:洞察现代数据栈技术的创新与发展(附大会核心PPT下载)

随着数字化浪潮的推进&#xff0c;数据已成为企业竞争的核心要素。为了应对日益增长的数据挑战&#xff0c;现代数据栈技术日益受到业界的关注。DataFunSummit 2023年现代数据栈技术峰会正是在这样的背景下应运而生&#xff0c;汇聚了全球数据领域的精英&#xff0c;共同探讨现…

Android应用开发data android:schemes标签的作用

文章目录 data android:schemesAndroidManifest.xml 中 <data> 元素的属性详解 data android:schemes 在 AndroidManifest.xml 文件中&#xff0c; 标签的作用是指定该应用可以处理的 URI 方案。 URI 是统一资源标识符&#xff0c;它是一种用于标识资源的标准方法。URI…

【三】【SQL Server】如何运用SQL Server中查询设计器通关数据库期末查询大题

数据库学生选择1122 数据库展示 course表展示 SC表展示 student表展示 数据库学生选课1122_1 第一题 第二题 第三题 第四题 第五题 数据库学生选课1122_2 第六题 第七题 第八题 第九题 第十题 结尾 最后&#xff0c;感谢您阅读我的文章&#xff0c;希望这些内容能够对您有所启…

列表吸顶分组之按首字母分组国家选区号

列表粘性分组之按首字母分组国家选区号 Android原生版本 直接先看UI图,效果如下 本来看起来也不难,我就想着上面常用区号那块不动,下面的列表滑动就行,但IOS说他滑动的时候上面也滑上去了,好吧,这也行;但最终效果做出来后,IOS滑动后会有按照国家名称首字母进行粘性分…

mysql从旧表 取出部分列并保存到新表几种方式介绍

在MySQL中&#xff0c;从旧表取出部分列并保存到新表有多种方式&#xff0c;主要包括以下几种&#xff1a; 1. 使用INSERT INTO ... SELECT语句&#xff1a; 这是最常用的方法。通过SELECT语句从旧表中选择需要的数据&#xff0c;然后使用INSERT INTO语句将数据…