MySQL 索引原理以及 SQL 优化

索引

  • 索引:一种有序的存储结构,按照单个或者多个列的值进行排序。
  • 索引的目的:提升搜索效率。
  • 索引分类:
    • 数据结构
      • B+ 树索引(映射的是磁盘数据)
      • hash 索引(快速锁定内存数据)
      • 全文索引
        • 将存储在数据库中的整本书和整篇文章中的任意内容信息查找出来的技术。
        • 在短字符串中用 LIKE %;在全文索引中用 match 和 against。
        • 一般使用 elasticsearch。
    • 物理存储
      • 聚集索引(聚簇索引):主键所对应的 B+ 树。(包含主键 ID 和表数据)
      • 辅助索引(二级索引):除了主键之外的其它索引。(只包含 key 和主键 ID)
        • 回表查询:辅助索引 B+ 树通过 key 查找到主键 ID,然后通过主键 ID 查找聚簇索引 B+ 树从而得到表记录。
      struct zcoder_tb {int id;       // primary keystring name;  // keystring phone; // keyshort age;
      }; map<int, zcoder_tb> // 聚簇索引
      map<string, int>    // 辅助索引
      map<string, int>    // 辅助索引
      
    • 列属性
      • 主键索引:非空唯一索引,一个表只有一个主键索引;在 innodb 中,主键索引的 B+ 树包含表数据信息
        PRIMARY KEY(key1, key2)
        
      • 唯一索引:不可以出现相同的值,可以有 NULL 值。
        UNIQUE(key1, key2)
        
      • 普通索引:允许出现相同的索引内容 。
        INDEX(key1, key2)
        -- OR
        KEY(key1, key2)
        
      • 前缀索引:只比较长字符串的前几个字符。
    • 列的个数
      • 单列索引
      • 组合索引:对表上的多个列进行索引。
        INDEX(key1, key2)
        UNIQUE(key1, key2)
        PRIMARY KEY(key1, key2)
        
  • 索引代价
    • 占用空间(有多个索引,就有多个 B+ 树)。
    • 维护的代价:DML 操作变慢(如果修改的字段有索引(非聚簇索引),除了要修改聚簇索引 B+ 树,还要修改对应的辅助索引 B+ 树)。
  • 索引的使用场景
    • where
    • group by
    • order by
  • 不使用索引的场景
    • 不使用 where / / /group by / / /order by
    • 列中的数据区分度不高
    • 经常修改的列
    • 表数据量少
  • innodb 中 B+ 树(多路平衡搜索树)
    在这里插入图片描述
    • 特征:
      • 非叶子节点只存储索引信息(只存储 key)。
      • 叶子节点还存储数据信息(存储 key 和 value)。
      • 叶子节点之间依次相连。
      • 节点的大小为 16 KB,映射的是连续的磁盘页(通过 mmap 映射磁盘数据)。
      • 一个叶子节点至少存储两行数据,如果某一行数据大于 16 KB,则会截取一部分数据进行存储,并保留一个地址位(记录另一个 B+ 树所对应的地址),然后把剩余的数据存储在另一个 B+ 树中。
    • 为什么采用 “多路” 的树结构
      • 一个节点多条链路,相较于平衡二叉搜索树是一个更加矮胖的结构,树的高度较低,较少的磁盘 IO 次数来索引数据。
    • 为什么非叶子节点只存储索引信息
      • B+ 树节点映射固定大小的磁盘数据,可以包含更多的索引信息,能快速锁定数据所在叶子节点的位置。
    • 为什么叶子节点依次相连
      • 便于范围查询,避免中序遍历回溯去查找下一个节点。
    • 索引信息和数据信息的分层管理,便于高效地组织磁盘数据,快速实现单点和范围查询。
  • 聚簇索引查找流程
select * from user where id >= 18 and id < 40;

在这里插入图片描述

  • 辅助索引查找流程
    • 辅助索引的叶子节点不包含行记录的全部数据,只存储了用来排序的 key 和一个 bookmark,该书签存储了聚集索引的 key。
-- 某个表 包含 id、name、lockyNum; id是主键,lockyNum 是辅助索引;
select * from user where lockyNum = 33;

在这里插入图片描述

  • innodb 体系结构
    在这里插入图片描述
    在这里插入图片描述
    • Buffer Pool
      • 缓存表和索引数据( 聚簇索引 B+ 树的数据)。
      • 采用 LRU 算法,只缓存比较热的数据。
      • 缓存大小为 128 MB。
      • 有三个链表组织数据
        • free list 组织 Buffer Pool 中未使用的缓存页。
        • flush list 组织 Buffer Pool 中的脏页,也就是待刷磁盘的页。
        • lru list 组织 Buffer Pool 中的冷热数据,当 Buffer Pool 没有空闲页时,将把 lru list 中最久未使用的数据淘汰。
      • Buffer Pool 中的数据修改没有刷到磁盘,怎么确保内存中数据安全(mysql 关闭时,内存数据丢失)?
        在这里插入图片描述
    • Change Buffer
      • Change Buffer 缓存辅助索引的数据变更(DML 操作),Change Buffer 中的数据将会异步 merge 到 Buffer Pool 中。

索引存储

  • innodb 由段、区、页组成,段分为数据段、索引段、回滚段等。区大小为 1 MB(一个区由 64 个连续页构成),页的默认值为 16 KB,页为逻辑页,磁盘物理页大小一般为 4KB 或者 8KB。
  • 为了保证区中的页连续,存储引擎一般一次从磁盘中申请 4~5 个区。
  • 顺序内存 IO(数组) > > >> >> 随机内存 IO(红黑树) ≈ \approx 顺序磁盘 IO > > >> >> 随机磁盘 IO
    在这里插入图片描述

索引覆盖

  • 一种数据查询方式。
  • 针对的是辅助索引。
  • 直接通过辅助索引 B+ 树就能获取要查询的值,而无需通过回表查询。
  • 在 select 中尽量写我们所需要的字段。

最左匹配规则

  • 针对组合索引。
  • 从左到右依次匹配,遇到 > 、 < 、 b e t w e e n 、 l i k e >、<、between、like ><betweenlike 就停止匹配。
  • 尽量扩展索引,而不是单独创建索引。

索引下推

  • 目的:减少回表次数,减少 server 层和存储引擎层的交互次数,从而提升查询效率。
  • 对象:辅助索引(普通索引和联合索引场景居多)。
  • 5.6 版本后支持。
  • 没有索引下推机制:server 层向存储引擎层请求数据,在 server 层根据索引条件进行数据过滤。
  • 有索引下推:将索引条件判断下推到存储引擎中过滤数据,最终由存储引擎进行数据汇总返回给 server 层。

索引失效

  • where
    • or 或 and,包含非索引字段。
    • in 子查询。
  • LIKE 模糊查询,通配符 % 开头。
    explain select * from zcoder_tb where name like '%张';
    
  • 索引字段参与运算。
    from_unixtime(idx) = '2024-02-21'; # 索引失效
    idx = unix_timestamp("2024-02-21") # 索引有效
    
  • 索引字段发生隐式转换。
    • 将列隐式转换为某个类型,实际等价于在索引列上作用了隐式转换函数。
  • 在索引字段上使用 NOT、<> 、!= 。
    id <> 0;            # 索引失效
    idx > 0 or idx < 0; # 索引有效
    
  • 组合索引中,没有使用第一列索引。

索引原则

  • 查询频次较高且数据量大的表建立索引,索引选择使用频次较高,过滤效果好的列或者组合。
  • 使用短索引,节点包含的信息多,较少磁盘 IO 操作。比如: smallint,tinyint。
  • 对于组合索引,考虑最左侧匹配原则和索引覆盖。
  • 尽量选择区分度高的列作为索引,该列的值相同的越少越好。
  • 尽量扩展索引,在现有索引的基础上,添加复合索引,最多 6 个索引。
  • 不要 select *,尽量只列出需要的列字段,方便使用索引覆盖。
  • 索引列,列尽量设置为非空。
  • 对于很长的动态字符串,考虑使用前缀索引。 注意:前缀索引不能做 order by 和 group by。
    有时候需要索引很长的字符串,这会让索引变的大且慢。
    通常情况下可以使用某个列开始的部分字符串作为索引,这样大大的节约索引空间,从而提高索引效率。
    但这会降低索引的区分度,索引的区分度是指不重复的索引值和数据表记录总数的比值。
    索引的区分度越高则查询效率越高,因为区分度更高的索引可以让 MySQL 在查找的时候过滤掉更多的行。
    对于 BLOB , TEXT , VARCHAR 类型的列,必要时使用前缀索引。
    因为 MySQL 不允许索引这些列的完整长度,使用该方法的诀窍在于要选择足够长的前缀以保证较高的区分度。select count(distinct left(name,3))/count(*) as sel3, count(distinct left(name,4))/count(*) as sel4, count(distinct left(name,5))/count(*) as sel5, count(distinct left(name,6))/count(*) as sel6, from user;
    alter table user add key(name(4));
    
  • 可选:开启自适应 hash 索引或者调整 Change Buffer。
    select @@innodb_adaptive_hash_index;
    set global innodb_adaptive_hash_index=1; -- 默认是开启的select @@innodb_change_buffer_max_size; -- 默认值为 25,表示最多使用 1/4 的缓冲池内存空间,最大值为 50
    set global innodb_change_buffer_max_size=30

出现了 SQL 比较慢,如何解决?

  1. 找到 SQL 语句
    • show processlist
      show processlist:查看连接线程,可以查看此时线上运行的 SQL 语句。
      如果要查看完整的 SQL 语句:SHOW FULL PROCESSLIST, 然后优化该语句。
      
    • 开启慢日志查询
      -- 查看
      SHOW GLOBAL VARIABLES LIKE 'slow_query%';
      SHOW GLOBAL VARIABLES LIKE 'long_query%';
      -- 设置
      SET GLOBAL slow_query_log = ON;  -- on 开启,off 关闭
      SET GLOBAL long_query_time = 4;  -- 单位秒;默认 10s;此时设置为 4s
      # 或者修改配置
      slow_query_log = ON
      long_query_time = 4
      slow_query_log_file = D:/mysql/mysql57-slow.log# 查找最近 10 条慢查询日志
      mysqldumpslow -s t -t 10 -g 'select' D:/mysql/mysql57-slow.log
      
  2. 分析 SQL 语句
    • 索引
      • where
      • group by
      • order by
    • SQL 语句
      • in 和 not in 优化成联合查询
      • 减少联合查询
    • 工作中不要用 age 字段,而是存储他的生日(年月日)

主键选择

  • innodb 中表是索引组织表,每张表有且仅有一个主键。
    • 如果显式设置 PRIMARY KEY,则该 key 作为该表的主键。
    • 如果没有显式设置,则从非空唯一索引中选择:
      • 只有一个非空唯一索引,则选择该索引为主键。
      • 有多个非空唯一索引,则选择声明的第一个作为主键。
    • 没有非空唯一索引,则自动生成一个 6 字节的 _rowid 作为主键。

约束

  • 为了实现数据的完整性,对于 innodb,提供了以下几种约束:
    primary keyunique keyforeign keydefaultnot null

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

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

相关文章

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(一)

在我们开始探索人工智能的世界时&#xff0c;了解如何与之有效沉浸交流是至关重要的。想象一下&#xff0c;你手中有一把钥匙&#xff0c;可以解锁与OpenAI的GPT模型沟通的无限可能。这把钥匙就是——正确的提示词&#xff08;prompts&#xff09;。无论你是AI领域的新手&#…

SpringCloud全家桶---常用微服务组件(1)

注册中心: *作用: 服务管理 Eureka(不推荐)[读音: 优瑞卡] Nacos(推荐) Zookeeper [读音: 如k波] Consul [读音:康寿] **注册中心的核心功能原理(nacos)** 服务注册: 当服务启动时,会通过rest接口请求的方式向Nacos注册自己的服务 服务心跳: NacosClient 会维护一个定时心跳持…

Sora背后的论文(1):使用 lstms 对视频展现进行无监督学习

之前那篇《Sora背后的32篇论文》发出后&#xff0c;大家都觉得不错&#xff0c;有很多小伙伴都开始啃论文了。 那么我就趁热打铁&#xff0c;把这32篇论文的通俗解读版贴一下。 从去年开始&#xff0c;我基本上形成了一个思维方式&#xff0c;任何事情做之前先看看 有没有好的…

个人博客系列-环境配置-gitee(2)

注册gitee账户 地址&#xff1a;https://gitee.com/ 此步骤省略 新建仓库 执行以下命令 即可 拉取代码 创建目录 mkdir myCode && cd myCode 登录gitee找到项目&#xff0c;点击克隆&#xff0c;拉取代码 连接远程仓库命令 git remote add origin 仓库地址http…

MariaDB落幕和思考

听过MySQL的基本也都知道 MariaDB。MariaDB由MySQL的创始人主导开发&#xff0c;他早前曾以10亿美元的价格&#xff0c;将自己创建的公司MySQL AB卖给了SUN&#xff0c;此后&#xff0c;随着SUN被甲骨文收购&#xff0c;MySQL的所有权也落入Oracle的手中。传闻MySQL的创始人担心…

创建型设计模式 - 原型设计模式 - JAVA

原型设计模式 一 .简介二. 案例三. 补充知识 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一 .简介 原型模式提供了一种机制&#xff0c;可以将原始对象复制到新对象&#xff0…

[TCP] TCP/IP 基础知识词典(2)

我想统计一下&#xff0c;TCP/IP 尤其是TCP协议&#xff0c;能搜到的常见的问题&#xff0c;整理起来&#xff0c;关键词添加在目录中&#xff0c;便于以后查阅。 目前预计整理共3篇&#xff1a; [TCP] TCP/IP 基础知识问答 &#xff1a;基础知识 [TCP] TCP/IP 基础知识问答&…

游戏平台如何定制开发?

随着科技的飞速发展和互联网的普及&#xff0c;游戏平台已成为人们休闲娱乐的重要选择。为了满足用户多样化的需求&#xff0c;游戏平台的定制开发显得尤为重要。本文将探讨游戏平台定制开发的过程、关键要素以及注意事项&#xff0c;为有志于涉足此领域的开发者提供参考。 一、…

ApexRBp在线粒子传感器在电动汽车电池制造的应用

电动汽车电池的崛起与颗粒污染的挑战 随着电动汽车&#xff08;EV&#xff09;市场的迅速扩张&#xff0c;对高性能锂离子电池的需求也急剧增加。这些电池不仅是EV的心脏&#xff0c;更是推动其前行的核心动力。然而&#xff0c;在电池制造的每一个环节&#xff0c;都需要对多…

【Python笔记-设计模式】适配器模式

一、说明 适配器模式是一种结构型模式&#xff0c;它使接口不兼容的对象能够相互合作 (一) 解决问题 主要解决接口不兼容问题 (二) 使用场景 当系统需要使用现有的类&#xff0c;但类的接口不符合需求时当需要一个统一的输出接口&#xff0c;但输入类型不可预知时当需要创…

查询数据库的编码集Oracle,MySQL

1、查询数据库的编码集Oracle,MySQL 1.1、oracle select * from v$nls_parameters where parameterNLS_CHARACTERSET; 查询版本&#xff1a;SELECT * FROM v$version 2、MySQL编码集 SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SC…

【了解机器学习的定义与发展历程】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱 简述概要 了解机器学习的定义与发展历程 知识图谱 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;是一门跨学科的学科&#xff0c;它使用计算机模拟或实现人类学习行为&#xff0c;通…

路由器的端口映射如何设置?

路由器的端口映射设置是网络连接中常用的配置功能&#xff0c;通过将外部网络访问请求映射到内部设备&#xff0c;实现局域网内设备的远程访问。本文将介绍如何进行路由器的端口映射设置&#xff0c;并以【天联】组网产品为例进行说明。 【天联】组网产品介绍 【天联】组网是一…

css3d制作正方体

使用css3d技术 &#xff0c;制作一个可以动态动画的正方体模型 效果图&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html> <head><style>/* 设置高度宽度100%并且左右居中、上下居中 */html,body {width: 100%;height: 100%;display: flex…

RENISHAW雷尼绍双读数头系统应用分享

在精密回转运动控制中&#xff0c;大多数场合都会对系统的回转定位精度有严格的要求&#xff0c;RENISHAW雷尼绍圆光栅系统&#xff08;RESM增量和RESA绝对值&#xff09;对于回转角度的反馈测量方案能有效的解决运动控制对回转精度的需求。但是配置单个读数头的圆光栅系统的精…

C#最优队列最小堆小顶堆大顶堆小根堆大根堆PriorityQueue的使用

最优队列有多种叫法&#xff0c;什么小根堆&#xff0c;大根堆&#xff0c;小顶堆&#xff0c;大顶堆。 队列分多种&#xff0c;线性队列&#xff08;简单队列&#xff09;&#xff0c;循环队列&#xff0c;最优队列等等。 最优队列&#xff0c;可以看作堆叠箱子&#xff0c;…

3分钟看懂设计模式01:策略模式

一、什么是策略模式 定义一些列算法类&#xff0c;将每一个算法封装起来&#xff0c;并让它们可以互相替换。 策略模式让算法独立于使用它的客户而变化&#xff0c;是一种对象行为型模式。 以上是策略模式的一般定义&#xff0c;属于是课本内容。 在没有真正理解策略模式之…

简单几步通过DD工具把云服务器系统Linux改为windows

简单几部通过DD安装其他系统&#xff0c;当服务器的web控制台没有我们要装的系统&#xff0c;就需要通过DD&#xff08;Linux磁盘&#xff09;工具来更改系统&#xff0c;&#xff08;已知支持KVM系统&#xff09; 本文如何简单的更换系统&#xff0c;不通过web控制台来更换&a…

Hive【内部表、外部表、临时表、分区表、分桶表】【总结】

目录 Hive的物种表结构特性 一、内部表 建表 使用场景 二、外部表 建表:关键词【EXTERNAL】 场景&#xff1a; 外部表与内部表可互相转换 三、临时表 建表 临时表横向对比​编辑 四、分区表 建表&#xff1a;关键字【PARTITIONED BY】 场景&#xff1a; 五、分桶表 …

算能RISC-V通用云开发空间编译pytorch @openKylin留档

终于可以体验下risc-v了&#xff01; 操作系统是openKylin&#xff0c;算能的云空间 尝试编译安装pytorch 首先安装git apt install git 然后下载pytorch和算能cpu的库&#xff1a; git clone https://github.com/sophgo/cpuinfo.git git clone https://github.com/pytorc…