Mysql 索引原理和优化方式

news2024/10/4 0:30:44

一、索引原理

什么是索引

索引是存储引擎用于快速找到记录的一种数据结构。可以联想到字典中的目录。

索引的分类

(1) Hash 索引

Hash 索引是比较常见的一种索引,他的单条记录查询的效率很高,时间复杂度为1。但是,Hash索引并不是最常用的数据库索引类型,尤其是我们常用的Mysql Innodb引擎就是不支持hash索引的。主要有以下原因:

Hash索引适合精确查找,但是范围查找不适合,因为存储引擎都会为每一行计算一个hash码,hash码都是比较小的,并且不同键值行的hash码通常是不一样的,hash索引中存储的就是Hash码,hash 码彼此之间是没有规律的;
且 Hash 操作并不能保证顺序性,所以值相近的两个数据,Hash值相差很远,被分到不同的桶中。这就是为什么hash索引只能进行全职匹配的查询,因为只有这样,hash码才能够匹配到数据。

(2) 二叉树

先来介绍下最经典的二叉树的特点:

  • 二叉树的时间复杂度为 O(n)
  • 一个节点只能有两个子节点。即度不超过2
  • 左子节点 小于 本节点,右子节点 大于 本节点

但是在极端情况下会出现链化的情况,即节点一直在某一边增加。

平衡二叉树(Balanced Binary Tree,简称 ABT)是一种特殊的二叉树,其中每个节点的左右子树的高度之差的绝对值不超过1,并且它的左子树和右子树都是平衡二叉树。平衡二叉树的特点:

  • 根节点会随着数据的改变而变更
  • 数据量越多,遍历次数越多,IO次数就越多,就越慢(磁盘的IO由树高决定)

(3)B-树

B-树是一棵多路平衡查找树,对于一棵M阶的B-树有以下的性质:

  • 根节点至少有两个子女.
  • 每个节点包含k-1个元素和k个孩子,其中m/2 <= k <= m.
  • 每一个叶子节点都包含k-1个元素,其中m/2 <= k <= m.
  • 所有的叶子节点位于同一层.
  • 每个节点中的元素从小到大排列,那么k-1个元素正好是k个孩子包含的值域的划分.

可以将B-树理解为一棵更加矮胖的二叉搜索树.
二叉搜索树(Binary Search Tree,简称 BST),是一种特殊的二叉树,其中每个节点的左子树的值都小于该节点的值,而每个节点的右子树的值都大于该节点的值。

(4)B+树

MySQL 中最常用的索引的数据结构是 B+ 树。B+树是B-树的进阶版本,在B-树的基础上又做了如下的限制:

  • 每个中间节点不保存数据,只用来索引,也就意味着所有非叶子节点的值都被保存了一份在叶子节点中.
  • 叶子节点之间根据自身的顺序进行了链接.

这样可以带来什么好处呢?

  • 中间节点不保存数据,那么就可以保存更多的索引,树的层级更少,减少数据库磁盘IO的次数.
  • 因为中间节点不保存数据,所以每一次的查找都会命中到叶子节点,而叶子节点是处在同一层的,因此查询的性能更加的稳定.
  • 所有的叶子节点按顺序链接成了链表,因此可以方便的话进行范围查询.

聚簇索引

聚簇索引不是一种索引类型,而是一种存储数据的方式。Innodb的聚簇索引是在同一个数据结构中同时保存了索引和数据.
mysql中,主键索引页+数据页组成的B+树就是聚簇索引。聚簇索引中数据页记录的是一条记录的完整的记录。

MySQL 在存储数据的时候是以数据页为最小单位的,且数据在数据页中的存储是连续的,数据页中的数据是按照主键排序的(没有主键是由 MySQL自己维护的 ROW_ID 来排序的),数据页和数据页之间是通过双向链表来关联的,数据与数据时间是通过单向链表来关联的。

也就是说有一个在每个数据页中,他必然就有一个最小的主键,然后每个数据页的页号和最小的主键会组成一个主键目录,假设现在要查找主键为 2 的数据,通过二分查找法最后确定下主键为 2 的记录在数据页 1 中,此时就会定位到数据页 1 接着再去定位主键为 2 的记录。

假设上面的主键目录中的记录是非常非常多的,此时MySQL 会将索引里面的记录拆分到不同的索引页中,最终演变成这个样子:

在这里插入图片描述
来自:https://zhuanlan.zhihu.com/p/394429932

刚刚上面是说的其实可以理解为是主键索引,主键索引也是最简单的最基础的索引。所以说建立了主键查询就能变快了。

如何查看索引的一些相关信息?

(1)索引信息

在mysql中,可以使用show create table table_name来查看建表语句,其中包含创建索引的语句:

在这里插入图片描述

可以使用show index from table_name来查看某个表上的索引,它将会有如下的输出:
在这里插入图片描述

可以看到,第一行默认使用了id 作为主索引。B+树在新增数据时,会根据主索引进行重整,影响性能,因此InnoDB推荐以自增id作为主索引:自增且连续,在插入的时候只需要不断的在数据后面追加即可。

后两行使用了联合索引,使用联合索引可以在多个列上进行快速的筛选和排序,特别适用于需要同时查询多个列的情况。
在创建联合索引时,需要注意以下几点:

  1. 列的顺序很重要:联合索引的效果与列的顺序有关。通常,将最常用于查询的列放在前面可以提高索引的效率。
  2. 列的选择要合理:不是所有的列都适合创建联合索引,只有在经常用于查询和筛选的列上创建索引才能发挥最大的作用。
  3. 索引的大小要控制:联合索引的大小会影响插入和更新的性能,因此需要根据实际情况控制索引的大小。

如果需要查询的字段不在联合索引中,MySQL 就需要进行回表查询了,如:

SELECT user_id,product_name,price FROM orders WHERE user_id='2' and product_name='Apple watch';

此时 MySQL 会再次根据主键从聚簇索引的根节点开始查找,这个过程就叫回表。

另外,每建立1个索引,MySQL 就会多维护1个B+树,所以不能建立太多索引,因为索引也会占用空间。

(2)索引大小

在5.0以后的版本中,我们可以通过查看information_schema.TABLES表中的数据来获取更加详细的数据.

该表各字段的含义如下表:

我们可以通过一些查询语句来获取详细的信息,比如:

// 查看当前MySQL服务器所有索引的大小(以MB为单位,默认是字节)
SELECT CONCAT(ROUND(SUM(index_length)/(1024*1024), 2), ' MB') AS 'Total Index Size' FROM TABLES
// 查看某一个库的所有大小
SELECT CONCAT(ROUND(SUM(index_length)/(1024*1024), 2), ' MB') AS 'Total Index Size' FROM TABLES  WHERE table_schema = 'XXX';
// 查看某一个表的索引大小
SELECT CONCAT(ROUND(SUM(index_length)/(1024*1024), 2), ' MB') AS 'Total Index Size' FROM TABLES  WHERE table_schema = 'yyyy' and table_name = "xxxxx";  
// 汇总查看一个库中的数据大小及索引大小
SELECT CONCAT(table_schema,'.',table_name) AS 'Table Name', CONCAT(ROUND(table_rows/1000000,4),'M') AS 'Number of Rows', CONCAT(ROUND(data_length/(1024*1024*1024),4),'G') AS 'Data Size', CONCAT(ROUND(index_length/(1024*1024*1024),4),'G') AS 'Index Size', CONCAT(ROUND((data_length+index_length)/(1024*1024*1024),4),'G') AS'Total'FROM information_schema.TABLES WHERE table_schema LIKE 'xxxxx';

注意:上面的表格是有缓存的,当更新数据库索引之后,最好执行analyze table xxxx,然后再进行查看.MySQL会在表格数据发生较大的变化时才更新此表(大小变化超过1/16或者插入20亿行).

(3) 索引碎片

在索引的创建删除过程中,不可避免的会产品索引碎片,当然还有数据碎片,我们可以通过执行optimize table xxx来重新整理索引及数据,对于不支持此命令的存储引擎来说,可以通过一条无意义的alter语句来触发整理,比如:将表的存储引擎更换为当前的引擎,alter table xxxx engine=innodb.

二、优化方式

1,系统优化:

  • 硬件:使用好的硬件,更快的硬盘、大内存、多核CPU,专业的存储服务器(NAS、SAN)

  • 架构:设计合理架构,如果 MySQL 访问频繁,考虑 Master/Slave 读写分离;数据库分表、数据库切片(分布式),也考虑使用相应缓存服务帮助 MySQL 缓解访问压力

2, 服务优化

(1)配置合理的MySQL服务器,尽量在应用本身达到一个MySQL最合理的使用
(2)针对 InnoDB 等不同引擎进行不同定制性配置
(3)针对不同的应用情况进行合理配置

公共选项:
在这里插入图片描述

Innodb选项:
在这里插入图片描述

华为云 RDS for MySQL参数调优建议:
https://support.huaweicloud.com/usermanual-rds/rds_08_00001.html

3, 应用优化

(1) 设计合理的数据表结构:适当的数据冗余
(2)对数据表建立合适有效的数据库索引
(3)数据查询:编写简洁高效的SQL语句

表结构设计原则

  • 选择合适的数据类型:如果能够定长尽量定长
  • 使用 ENUM 而不是 VARCHAR,ENUM类型是非常快和紧凑的,在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来做一些选项列表变得相当的完美 。
  • 不要使用无法加索引的类型作为关键字段,比如 text类型
  • 为了避免联表查询,有时候可以适当的数据冗余,比如 邮箱、姓名这些不容易更改的数据
  • 选择合适的表引擎,有时候 MyISAM 适合,有时候 InnoDB适合
  • 为保证查询性能,最好每个表都建立有 auto_increment 字段, 建立合适的数据库索引
  • 最好给每个字段都设定 default 值

索引建立原则

  • 一般针对数据分散的关键字进行建立索引,比如ID、QQ,像性别、状态值等等建立索引没有意义
  • 字段唯一,最少,不可为null
  • 对大数据量表建立聚集索引,避免更新操作带来的碎片。
  • 尽量使用短索引,一般对int、char/varchar、date/time 等类型的字段建立索引
  • 需要的时候建立联合索引,但是要注意查询SQL语句的编写
  • 谨慎建立 unique 类型的索引(唯一索引)
  • 大文本字段不建立为索引,如果要对大文本字段进行检索,可以考虑全文索引
  • 频繁更新的列不适合建立索引
  • order by 字句中的字段,where 子句中字段,最常用的sql语句中字段,应建立索引。
  • 唯一性约束,系统将默认为改字段建立索引。
  • 对于只是做查询用的数据库索引越多越好,但对于在线实时系统建议控制在5个以内。
  • 索引不仅能提高查询SQL性能,同时也可以提高带where字句的update,Delete SQL性能。
  • Decimal 类型字段不要单独建立为索引,但覆盖索引可以包含这些字段。
  • 只有建立索引以后,表内的行才按照特地的顺序存储,按照需要可以是asc或desc方式。
  • 如果索引由多个字段组成将最常用来查询过滤的字段放在前面可能会有更好的性能。

编写高效的 SQL

  • 能够快速缩小结果集的 WHERE 条件写在前面,如果有恒量条件,也尽量放在前面
  • 尽量避免使用 GROUP BY、DISTINCT 、OR、IN 等语句的使用,避免使用联表查询和子查询,因为将使执行效率大大下降
  • 能够使用索引的字段尽量进行有效的合理排列,如果使用了联合索引,请注意提取字段的前后顺序
  • 针对索引字段使用 >, >=, =, <, <=, IF NULL和BETWEEN 将会使用索引, 如果对某个索引字段进行 LIKE 查询,使用 LIKE ‘%abc%’ 不能使用索引,使用 LIKE ‘abc%’ 将能够使用索引
  • 如果在SQL里使用了MySQL部分自带函数,索引将失效,同时将无法使用 MySQL 的 Query Cache,比如 LEFT(), SUBSTR(), TO_DAYS() DATE_FORMAT(), 等,如果使用了 OR 或 IN,索引也将失效
  • 使用 Explain 语句来帮助改进我们的SQL语句
  • 不要在where 子句中的“=”左边进行算术或表达式运算,否则系统将可能无法正确使用索引
  • 尽量不要在where条件中使用函数,否则将不能使用索引
  • 避免使用 select *, 只取需要的字段
  • 对于大数据量的查询,尽量避免在SQL语句中使用order by 字句,避免额为的开销,替代为使用ADO.NET 来实现。
  • 如果插入的数据量很大,用select into 替代 insert into 能带来更好的性能
  • 采用连接操作,避免过多的子查询,产生的CPU和IO开销
  • 只关心需要的表和满足条件的数据
  • 适当使用临时表或表变量
  • 对于连续的数值,使用between代替in
  • where 字句中尽量不要使用CASE条件
  • 尽量不用触发器,特别是在大数据表上
  • 更新触发器如果不是所有情况下都需要触发,应根据业务需要加上必要判断条件
  • 使用union all 操作代替OR操作,注意此时需要注意一点查询条件可以使用聚集索引,如果是非聚集索引将起到相反的结果
  • 当只要一行数据时使用 LIMIT 1
  • 尽可能的使用 NOT NULL填充数据库
  • 拆分大的 DELETE 或 INSERT 语句
  • 批量提交SQL语句

常用技巧

  • 使用 Explain/ DESC 来分析SQL的执行情况
  • 使用 SHOW PROCESSLIST 来查看当前MySQL服务器线程执行情况,是否锁表,查看相应的SQL语句
  • 设置 my.cnf 中的 long-query-time 和 log-slow-queries 能够记录服务器那些SQL执行速度比较慢
  • 另外有用的几个查询:SHOW VARIABLES、SHOW STATUS、SHOW ENGINES
  • 使用 DESC TABLE xxx 来查看表结构,使用 SHOW INDEX FROM xxx 来查看表索引
  • 使用 LOAD DATA 导入数据比 INSERT INTO 快多了
  • SELECT COUNT(*) FROM Tbl 在 InnoDB 中将会扫描全表
  • Explain 使用。 语法:EXPLAIN SELECT select_options

Type: 类型,是否使用了索引还是全表扫描, const,eg_reg,ref,range,index,ALL
Key: 实际使用上的索引是哪个字段
Ken_len: 真正使用了哪些索引,不为 NULL 的就是真实使用的索引
Ref: 显示了哪些字段或者常量被用来和 key 配合从表中查询记录出来
Rows: 显示了MySQL认为在查询中应该检索的记录数
Extra: 显示了查询中MySQL的附加信息,关心Using filesort 和 Using temporary,性能杀手

参考:
https://zhuanlan.zhihu.com/p/394429932
https://zhuanlan.zhihu.com/p/76355753

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

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

相关文章

《红蓝攻防对抗实战》四.内网探测协议出网之ICMP协议探测出网

目录 一.Windows系统探测ICMP协议出网 1. Ping命令 2.Tracert 命令 二.Linux系统探测ICMP协议出网 1. Ping命令 ICMP&#xff08;Internet Control Message Protocol&#xff09;是一种面向无连接的协议&#xff0c;属于网络层的协议&#xff0c;用于检测网络通信故障和实…

MySQL中的表操作,配置文件,储存引擎,数据类型

MySQL中的表操作 1 查库&#xff08;已密码登陆mysql&#xff09; show databases; 2 添加库 create database t1; 3 表操作 1选定操作库 use t1 2在库里添加表格式 create table t1(id int, name varchar(32), gender varchar(32),age int); 3往表里添加具体元素 insert…

HDMI ——CEC 协议详解以及待机唤醒 实现

本文讲解的是基于HDMI CEC的待机唤醒方案的设计。 目录 cec基本介绍 CEC协议时序&#xff1a; CEC数据帧 cec待机唤醒介绍 待机唤醒的处理流程和实现 cec基本介绍 如今常见的高清视频接口有HDMI,VGA,DP和DVI。HDMI&#xff08;High-Definition Multimedia Interface&…

嵌入式linux系统设备树实例分析

前言 我们可以从LED程序中榨取很多知识&#xff1a;基本的驱动框架、驱动的简单分层、驱动的分层分离思想、总线设备驱动模型、设备树等。这大多都是结合韦老师的教程学的。 这篇笔记结合第6个demo&#xff08;基于设备树&#xff09;来学习、分析&#xff1a; 框图 下面是L…

10 创建型模式-原型模式

引言&#xff1a; 创建对象的五种方式&#xff1a; 通过new关键字通过Class类的newInstance()方法通过Constructor类的newInstance()方法利用Clone方法反序列化 Clone方法&#xff1a; 其实现方式正是通过调用 Object 类的 clone() 方法来完成。 protected native Object cl…

python安装.whl文件

python --version https://www.lfd.uci.edu/~gohlke/pythonlibs/ 用CtrlF找需要安装的包 下载对应版本的whl python3.8 把下载好的whl放到安装路径下&#xff1a;C:\Users\Administrator\AppData\Local\Programs\Python\Python38\Lib\site-packages 并在该路径下打开cmd执行…

GaussDB数据库管理系统介绍

1.GaussDB的发展 2.GaussDB的生态 内部&#xff1a; 云化自动化方案。通过数据库运行基础设施的云化将DBA(数据库管理员)和运维人员的日常工作 自动化。外部&#xff1a; 采用与数据库周边生态伙伴对接与认证的生态连接融合方案&#xff0c;解决开发者/DBA难获取、应用难对接等…

Linux绝对路径和相对路径

在 Linux 中&#xff0c;简单的理解一个文件的路径&#xff0c;指的就是该文件存放的位置。 只要我们告诉 Linux 系统某个文件存放的准确位置&#xff0c;那么它就可以找到这个文件。指明一个文件存放的位置&#xff0c;有 2 种方法&#xff0c;分别是使用绝对路径和相对路径。…

【驱动开发】LED灯的亮灭——通过字符设备驱动的分步实现编写LED驱动,实现设备文件和设备的绑定

头文件&#xff1a; #ifndef __HEAD_H__ #define __HEAD_H__typedef struct {unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t;//LED灯的寄存器地址 #define LED1_ADDR 0X50006000 #define L…

深入理解Redis集群模式、协议、元数据维护方式

文章目录 &#x1f34a; 集群模式&#x1f34a; 集群协议&#x1f34a; 元数据维护方式&#x1f389; 集中式&#x1f389; gossip 协议 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出…

适用于 Linux 和 Unix 的特权访问管理

凭据、SSH 密钥、服务帐户、数字签名、文件系统等内容构成了Linux 环境的关键部分&#xff0c;虽然大多数PAM供应商为基于Windows的环境提供无缝的特权访问管理&#xff0c;但它们的通用性不足以为Linux&#xff0c;Unix和*nix环境扩展相同的功能和功能。 Linux 中的root权限是…

redis的key超时策略和key淘汰机制(面试题详解)

ChatGPT给出的回答&#xff1a; Redis中的Key超时策略和Key淘汰机制是为了有效管理内存和控制数据的生命周期。 Key超时策略&#xff1a;Redis可以为每个Key设置过期时间&#xff0c;一旦Key过期&#xff0c;它将自动从Redis中删除。可以使用EXPIRE命令为Key设置过期时间&…

系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第六部分:开发运维

本心、输入输出、结果 文章目录 系统设计 - 我们如何通俗的理解那些技术的运行原理 - 第六部分&#xff1a;开发运维前言DevOps vs. SRE vs. Platform Engineering。有什么区别&#xff1f;什么是k8s&#xff08;Kubernetes&#xff09;&#xff1f;控制面板组件节点 Docker vs…

关于阿里云服务器续费详细流程_优惠续费方法

阿里云服务器如何续费&#xff1f;续费流程来了&#xff0c;在云服务器ECS管理控制台选择续费实例、续费时长和续费优惠券&#xff0c;然后提交订单&#xff0c;分分钟即可完成阿里云服务器续费流程&#xff0c;阿里云服务器网分享阿里云服务器详细续费方法&#xff0c;看这一篇…

【代码随想录】算法训练营 第十三天 第五章 栈与队列 Part 3

239. 滑动窗口最大值 题目 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 思路 一开始我是直接暴力两层循环的&#xff…

Python学习笔记——MYSQL,SQL核心

食用说明&#xff1a;本笔记适用于有一定编程基础的伙伴们。希望有助于各位&#xff01; SQL语言分类 SQL注释 库管理 表管理 数据操作 分组聚合 分页限制 需要注意的是关键字的顺序不可以错乱&#xff0c;否则会报错其中LIMIT关键字的n是指从第n个开始&#xff0c;m是指查…

http post协议实现简单的rpc协议,WireShark抓包分析

文章目录 1.http 客户端-RPC客户端1.http 服务端-RPC服务端3.WireShark抓包分析3.1客户端到服务端的HTTP/JSON报文3.2服务端到客户端的HTTP/JSON报文 1.http 客户端-RPC客户端 import json import requests# 定义 RPC 客户端类 class RPCClient:def __init__(self, server_url…

【蓝桥杯选拔赛真题43】python二进制位数 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析

目录 python二进制位数 一、题目要求 1、编程实现 2、输入输出 二、算法分析

深入浅出Apache SeaTunnel SQL Server Sink Connector

在大数据时代&#xff0c;数据的迁移和流动已经变得日益重要。为了使数据能够更加高效地从一个源流向另一个目标&#xff0c;我们需要可靠、高效和易于配置的工具。今天&#xff0c;我们将介绍 JDBC SQL Server Sink Connector&#xff0c;这是一个专为 SQL Server 设计的连接器…

嵌入式linux总线设备驱动模型分析

嵌入式linux系统按照&#xff0c;分层&#xff0c;抽象的思想&#xff0c;按照这样的思想来设计我们的程序可以更容易写出耦合性低、独立性强、可重用性强的代码。 Linux内核中更是存在着更多的分离、分层思想的代码&#xff0c;platform平台设备驱动就是用了这样的思想。本篇…