当前位置: 首页 > news >正文

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

相关文章:

MySQL 索引原理以及 SQL 优化

索引 索引&#xff1a;一种有序的存储结构&#xff0c;按照单个或者多个列的值进行排序。索引的目的&#xff1a;提升搜索效率。索引分类&#xff1a; 数据结构 B 树索引&#xff08;映射的是磁盘数据&#xff09;hash 索引&#xff08;快速锁定内存数据&#xff09;全文索引 …...

C++学习Day08之函数模板和普通函数的区别以及调用规则

目录 一、程序及输出1.1 区别1.1.1 自动类型推导&#xff0c;不可以发生隐式类型转换的1.1.2 普通函数 可以发生隐式类型转换 1.2 调用规则 二、分析与总结 一、程序及输出 1.1 区别 1.1.1 自动类型推导&#xff0c;不可以发生隐式类型转换的 1.1.2 普通函数 可以发生隐式类型…...

Kaggle实践之《Home Credit Default Risk》的逐步优化

记录下每一次的改进及其score。 1、只用训练集的特征简单处理 特征只用训练集的特征&#xff0c;把string型的特征全部进行one-hot转化&#xff0c;然后随机1:4分成测试集训练集&#xff0c;模型也调参直接出结果。 最终的score是训练集80.13%、验证集76.33%、线上74.28%。 …...

django rest framework 学习笔记-实战商城2

01收货地址模型类和视图定义_哔哩哔哩_bilibili 本博客借鉴至大佬的视频学习笔记 地址信息的管理&#xff1a;增删改查的实现 # 序列化器配置 class AddrSerializer(serializers.ModelSerializer):"""收货地址的模型序列化器"""class Meta:mo…...

WEB 3D技术 three.js 3D贺卡(4) 添加鼠标滚轮移动屏幕 改变贺卡文字功能

好&#xff0c;上文 WEB 3D技术 three.js 3D贺卡(3) 点光源灯光动画效果 那么 我们来做一下 鼠标滚动相机和滚动时不同文字的切换 首先 我们要设置多个场景 其实也不能完全叫场景 也可以说多个位置 反正简单说就是多个位置 展现多个场景 我们先在代码的最下面 加上一个对象数…...

爬虫在网页抓取的过程中可能会遇到哪些问题?

在网页抓取&#xff08;爬虫&#xff09;过程中&#xff0c;开发者可能会遇到多种问题&#xff0c;以下是一些常见问题及其解决方案&#xff1a; 1. IP封锁&#xff1a; 问题&#xff1a;封IP是最常见的问题&#xff0c;抓取的目标网站会识别并封锁频繁请求的IP地址。 解决方案…...

Eclipse中Run As On Server和Run As Java Application

一、名词释义 run java application &#xff08;作为Java应用程序运行&#xff09;是运行 java main方法。 run on server是启动一个web 应用服务器。 二、两者的区别 Eclipse中可以创建java project 也可以创建java web poject 。java project是可以直接在命令行运行,或者…...

【MySQL】库的操作——MySQL数据库 、库的操作、表的操作、字符集和校验规则、备份和恢复

文章目录 MySQL1. 库的操作2. 表的操作3. 字符集和校验规则3.1 查看系统默认字符集以及校验规则3.2 查看数据库支持的字符集3.3 查看数据库支持的字符集校验规则 4. 备份和恢复4.1 备份4.2 还原 MySQL 1. 库的操作 连接服务器 mysql -h 127.0.0.1 -P 3306 -u root -pmysql -u…...

pytorch 用F.normalization的逆归一化如何操作

逆归一化的时候再把这个数乘回去就行了 magnitude a.norm(p2, dim1, keepdimTrue) # NEW atorch.nn.functional.normalize(a, p2, dim1) a_or a* magnitude # NEW print(a_or) Outputs: tensor([]1,2,3)...

LabVIEW多通道压力传感器实时动态检测

LabVIEW多通道压力传感器实时动态检测 介绍了一种基于LabVIEW的多通道压力传感器实时动态检测系统&#xff0c;解决压阻式压力传感器温度补偿过程的复杂度&#xff0c;提高测量的准确性。通过自动轮询检测方法&#xff0c;结合硬件检测模型和多通道检测系统设计&#xff0c;本…...

Jenkins解决Host key verification failed (2)

Jenkins解决Host key verification failed 分析原因情况 一、用OpenSSH的人都知ssh会把你每个你访问过计算机的公钥(public key)都记录在~/.ssh/known_hosts。当下次访问相同计算机时&#xff0c;OpenSSH会核对公钥。如果公钥不同&#xff0c;OpenSSH会发出警告&#xff0c;避免…...

C#,数值计算,矩阵的乔莱斯基分解(Cholesky decomposition)算法与源代码

一、安德烈路易斯乔尔斯基 安德烈路易斯乔尔斯基出生于法国波尔多以北的查伦特斯海域的蒙古扬。他在波尔多参加了Lyce e&#xff0c;并于1892年11月14日获得学士学位的第一部分&#xff0c;于1893年7月24日获得第二部分。1895年10月15日&#xff0c;乔尔斯基进入莱科尔理工学院…...

docker 备份 mysql

使用 Docker 执行 MySQL 备份是一个实用的操作&#xff0c;可以帮助你确保数据的安全性和可恢复性。这里有一步步的指导帮你完成&#xff1a; 1. 确定 MySQL 容器名称或 ID 首先&#xff0c;你需要知道运行 MySQL 数据库的容器的名称或 ID。可以通过下面的命令查看所有正在运…...

使用C# Net6连接国产达梦数据库记录

达梦官网&#xff1a;http://www.dameng.com/ 1 下载达梦并进行安装 下载地址&#xff1a;官网首页——服务与合作——下载中心&#xff08;https://www.dameng.com/list_103.html&#xff09; 根据需要自行下载需要的版本&#xff0c;测试版本为&#xff1a;x86 win64 DM8版…...

docker (八)-dockerfile制作镜像

一 dockerfile dockerfile通常包含以下几个常用命令&#xff1a; FROM ubuntu:18.04 WORKDIR /app COPY . . RUN make . CMD python app.py EXPOSE 80 FROM 打包使用的基础镜像WORKDIR 相当于cd命令&#xff0c;进入工作目录COPY 将宿主机的文件复制到容器内RUN 打包时执…...

springcloud-网关(gateway)

springcloud-网关(gateway) 概述 \Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API&#xff0c;并为其提供跨领域的关注&#xff0c;如&#xff1a;安全、监控/指标和容错 常用术语 Route&#xff08;路由&#xff09;: 网关的基本构件。它由一个ID、一个目的地…...

2.20 day2 QT

自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {//窗口相关设置this->setWindowTitle("登入页面"); //设置 窗口 标题this->setWindowIcon(QIcon("D:…...

【C++语法基础】4.分支和循环结构(✨新手推荐阅读)

前言 在C编程中&#xff0c;分支和循环结构是控制程序流程的基本工具。分支结构允许程序根据特定条件执行不同的代码块&#xff0c;而循环结构则允许程序重复执行某个代码块。 分支结构 if 语句 if 语句是最基本的分支结构&#xff0c;它根据条件的真假来决定是否执行某段代…...

朋友圈程序全开源版源码,附带系统搭建教程

前台一键发布图文&#xff0c;视频&#xff0c;音乐。发布内容支持定位或自定义位置信息。支持将发布内容设为广告模式消息站内通知或邮件通知。支持其他用户注册,支持其他用户发布文章,管理自己的文章。拥有丰富的后台管理功能&#xff0c;一键操作。安装环境 Nginx ≥1.22 …...

思维方式系列文章目录 -《清单革命》实践

思维方式系列文章目录 -《清单革命》 文章目录 思维方式系列文章目录 -《清单革命》前言一、《清单革命》思维导图二、清单制作原则 前言 请记住&#xff0c;现在开始心灵转变&#xff0c;人人都会犯错&#xff0c;而错误分为&#xff1a;无知之错、无能之错。 无知之错&#…...

RAID 创建使用以及ubuntu安装和使用zfs文件系统及Ubuntu软件安装

RAID 创建使用 部署 RAID 10 的学习 1. 搭建 RAID 10 就是 RAID 1 加上 RAID 0,准备四块磁盘&#xff0c;用于创建 RAID 10,配置vmware虚拟机&#xff0c;创建四个虚拟硬盘。 2. 检查磁盘信息 rootubuntu:~# ls /dev/sd* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/s…...

yarn常用命令小记

安装 npm install -g yarn查看版本 yarn -v初始化项目与依赖管理 yarn init&#xff1a;与npm init一样通过交互式会话生成一个新的package.jason文件以初始化项目&#xff1b;跳过会话可使用yarn init --yes&#xff0c;简写yarn init -yyarn add <package><versi…...

防御保护---内容保护

文章目录 目录 文章目录 一.防火墙内容安全概述 二.深度识别技术&#xff08;DFI/DPI&#xff09; 深度包检测技术&#xff08;DPI&#xff09; 深度流检测技术&#xff08;DFI&#xff09; 两者区别 三.入侵防御IPS 一.防火墙内容安全概述 防火墙内容安全是防火墙的一个重…...

jquery将网页html文档导出为pdf图片

jquery将网页html文档导出为pdf图片 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…...

opengl 学习着色器

一.GLSL 着色器是使用一种叫GLSL的类C语言写成的。GLSL着色器编码顺序&#xff1a;声明版本》定义输入输出》uniform》main函数。每个着色器的入口点是main函数&#xff0c;在main函数中我们处理所有的输入变量&#xff0c;并将结果输出到输出变量中。如下图&#xff1a; #ver…...

【数据结构】18 二叉搜索树(查找,插入,删除)

定义 二叉搜索树也叫二叉排序树或者二叉查找树。它是一种对排序和查找都很有用的特殊二叉树。 一个二叉搜索树可以为空&#xff0c;如果它不为空&#xff0c;它将满足以下性质&#xff1a; 非空左子树的所有键值小于其根节点的键值非空右子树的所有键值都大于其根结点的键值左…...

力扣日记2.20-【回溯算法篇】491. 非递减子序列

力扣日记&#xff1a;【回溯算法篇】491. 非递减子序列 日期&#xff1a;2023.2.20 参考&#xff1a;代码随想录、力扣 ps&#xff1a;放了个寒假&#xff0c;日记又搁置了三星期……&#xff08;下跪忏悔&#xff09; 491. 非递减子序列 题目描述 难度&#xff1a;中等 给你一…...

Android 13.0 SystemUI下拉状态栏定制二 锁屏页面横竖屏解锁图标置顶显示功能实现

1.前言 在13.0的系统rom定制化开发中,在关于systemui的锁屏页面功能定制中,由于在平板横屏锁屏功能中,时钟显示的很大,并且是在左旁边居中显示的, 由于需要和竖屏显示一样,所以就需要用到小时钟显示,然后同样需要居中,所以就来分析下相关的源码,来实现具体的功能 如图…...

FPGA_简单工程_拨码开关

一 框图 二 波形图 三 代码 3.1 工程代码 module bomakiaguan (input [15:0] switch, // 输入16路拨码开关output reg [15:0] led // 输出16个LED灯 );always (switch) beginled < switch; // 将拨码开关的值直接赋给LED灯 end // 将拨码开关的值直接赋给LED灯 endmodu…...

LaunchPad 市场的复苏,Penpad 成新兴生力军

以 Fair Launch 为主要启动方式的铭文市场的爆发&#xff0c;推动了 LaunchPad 市场的复苏&#xff0c;绝多数所铭文项目都能通过 Fairr Launch 的方式筹集资金实现启动&#xff0c;该赛道的爆发不仅推动了数百亿美元的热钱开始在链上不断涌动&#xff0c;同时也进一步形成了新…...