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 作为主键。

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

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

相关文章

【Java EE初阶二十一】http的简单理解(二)

2. 深入学习http 2.5 关于referer Referer 描述了当前页面是从哪个页面跳转来的&#xff0c;如果是直接在地址栏输入 url(或者点击收藏夹中的按钮) 都是没有 Referer。如下图所示&#xff1a; HTTP 最大的问题在于"明文传输”,明文传输就容易被第三方获取并篡改. …

Android反编译工具及使用说明

文章目录 一、反编译常用的工具二、反编译工具的下载安装及使用1. Apktool下载使用 2. dex2jar下载使用 3. jd-gui下载使用 一、反编译常用的工具 Apktool 获取apk里的资源文件、配置文件、清单文件、lib文件夹下的so包等等dex2jar 将apk反编译成java源码&#xff0c;及dex文件…

Stable Diffusion 绘画入门教程(webui)-ControlNet(姿态预处理器openpose)

本片文章接着上篇文章ControlNet介绍他的控制类型&#xff0c;本篇介绍的预处理器为openpose 预处理器&#xff1a;openpose 模型&#xff1a;control_v11p_sd15_openpose 没下载模型的看上篇文章去下载一下哦&#xff0c;不然用不了 文章目录 一、干什么用的二、详细用法1、选…

Django使用Celery异步

安装包 pip install celerypip install eventlet 1.在项目文件的根目录下创建目录结果 2. 在main.py文件中 # !/usr/bin/env python # -*-coding:utf-8 -*-""" # Author &#xff1a;skyTree # version &#xff1a;python 3.11 # Description&#…

Git合并固定分支的某一部分至当前分支

在 Git 中&#xff0c;通常使用 git merge 命令来将一个分支的更改合并到另一个分支。如果你只想合并某个分支的一部分代码&#xff0c;可以使用以下两种方法&#xff1a; 1.批量文件合并 1.1.创建并切换到一个新的临时分支 首先&#xff0c;从要合并的源分支&#xff08;即要…

前端基础自学整理|HTML + JavaScript + DOM事件

目录 一、HTML 1、Html标签 2、Html元素 3、基本的HTML标签 二、CSS 样式 层叠样式表 三、JavaScript 使用示例 四、HTML DOM 通过可编程的对象模型&#xff0c;javaScript可以&#xff1a; window document 1、查找HTML元素 2、操作HTML元素 获取元素的属性 四…

Qt应用-天气预报实例

本文讲解Qt实现天气预报实例。 实现的功能 网络实时获取和显示6天的天气参数并绘制温度趋势曲线; 测试当前网络连接情况; 获得当前的IP地址的行政位置信息; 设计界面如下: 创建保存天气数据的类 #ifndef WEATHERDATA_H #define WEATHERDATA_H #include <QString>…

【C++】1006 - 打印星号三角形 1007 - 统计大写英文字母的个数 1008 - 字符图形9-数字正三角

文章目录 问题一&#xff1a;1006 - 打印星号三角形题目描述&#xff1a;输入&#xff1a;输出&#xff1a;样例&#xff1a;1.分析问题2.定义变量3.输入数据4.数据计算5.输出结果 问题二&#xff1a;1007 - 统计大写英文字母的个数题目描述&#xff1a;输入&#xff1a;输出&a…

解决弹性布局父元素设置高自动换行,子元素均分高度问题(align-content: flex-start)

案例&#xff1a; <view class"abc"><view class"abc-item" v-for"(item,index) in 8" :key"index">看我</view> </view> <style lang"less">.abc{height: 100px;display: flex;flex-wrap: …

【深入理解设计模式】 工厂设计模式

工厂设计模式 工厂设计模式是一种创建型设计模式&#xff0c;它提供了一种在不指定具体类的情况下创建对象的接口。在工厂设计模式中&#xff0c;我们定义一个创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 工厂设计模式的目…

centos 9 编译安装 LAMP wordpress

[rootlocalhost ~]# ll 总用量 655760 -rw-------. 1 root root 1040 2月 17 16:57 anaconda-ks.cfg drwxr-xr-x. 29 501 games 4096 2月 21 11:00 apr-1.7.4 -rw-r--r--. 1 root root 1122147 2月 21 10:57 apr-1.7.4.tar.gz drwxr-xr-x. 21 501 games …

四、分类算法 - 随机森林

目录 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结 sklearn转换器和估算器KNN算法模型选择和调优朴素贝叶斯算法决策树随机森林 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结

【Python】2019年蓝桥杯省赛真题——完全二叉树的权值

蓝桥杯 2019 省 A&B&#xff1a;完全二叉树的权值 题目描述 给定一棵包含 N N N 个节点的完全二叉树&#xff0c;树上每个节点都有一个权值&#xff0c;按从上到下、从左到右的顺序依次是 A 1 , A 2 , ⋯ A N A_1,A_2, \cdots A_N A1​,A2​,⋯AN​&#xff0c;如下图所…

《咸鱼之王》简单拆解图(持续更新)

文章目录 一、 介绍二、 角色设定阿咸咸将 三、游戏拆解 一、 介绍 《咸鱼之王》是一款由阿咸工作室开发的手机游戏&#xff0c;战斗方式为回合制卡牌对战&#xff0c;同时玩家点击屏幕可以为阵容提供助攻。该游戏于2021年3月4日公测。 在游戏中&#xff0c;玩家将化身主角阿…

Spring学习笔记(三)--Spring中的Bean的管理

一、什么是Bean Bean是注册到Spring容器中的Java类&#xff0c;控制反转和依赖注入都是通过Bean实现的&#xff0c;任何一个Java类都可以是一个Bean。Bean由Spring进行管理&#xff0c;可以通过xml文件对bean进行配置和管理。 二、BeanFactory接口和ApplicationContext接口&a…

重新安装VSCode后,按住Ctrl(or Command) 点击鼠标左键不跳转问题

重新安装VSCode后&#xff0c;按住Ctrl&#xff08;or Command&#xff09; 点击鼠标左键不跳转问题 原因&#xff1a;重新安装一般是因为相应编程语言的插件被删除了或还没有下载。 本次是由于Python相关的插件被删除了&#xff0c;因此导致Python无法跳转。 解决办法 在vs…

船运物流管理系统|基于springboot船运物流管理系统设计与实现(源码+数据库+文档)

船运物流管理系统目录 目录 基于springboot船运物流管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员登录 2、货运单管理 3、公告管理 4、公告类型管理 5、新闻管理 6、新闻类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 …

ElasticSearch语法

Elasticsearch 概念 入门学习: Index索引>MySQL 里的表(table)建表、增删改查(查询需要花费的学习时间最多)用客户端去调用 ElasticSearch(3 种)语法:SQL、代码的方法(4 种语法) ES 相比于 MySQL&#xff0c;能够自动帮我们做分词&#xff0c;能够非常高效、灵活地查询内…

【算法 - 动态规划】最长回文子序列

上篇文章中&#xff0c;我们学习一个新的模型&#xff1a; 样本对应模型&#xff0c;该模型的套路就是&#xff1a;以结尾位置为出发点&#xff0c;思考两个样本的结尾都会产生哪些可能性 。 而前篇文章中的 纸牌博弈问题 属于 [L , R]上范围尝试模型。该模型给定一个范围&…

初阶数据结构之---顺序表和链表(C语言)

引言-线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连续的一条直线。但在物理上并不一定是连续的。线性表在物理上…