MySQL创建联合索引,字段的先后顺序,对查询的影响分析

文章目录

  • 前言
    • 最左匹配原则
      • 为什么会有最左前缀呢?
      • 联合索引的存储结构
      • 联合索引字段的先后顺序
      • b+树可以存储的数据条数
  • 总结

前言

​ 对于联合索引我们知道,在使用的时候有一个最左前缀的原则,除了这些呢,比如字段放置的位置,会不会对索引的效率产生影响呢?

  • 最左匹配原则

​ 联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配,示例:

create table test
(id       bigint auto_incrementprimary key,column_1 bigint null,column_2 bigint null,column_3 bigint null
);create index test_column_1_column_2_column_3_indexon test (column_1, column_2, column_3);

​ 比如上面的test表,我们建立了联合索引index test_column_1_column_2_column_3_index on test (column_1, column_2, column_3);当我们进行查询的时候,按照最左前缀的原则,当查询(column_1)、(column_1,column_2)(column_1,column_2,column_3)这三种组合是可以用到我们定义的联合索引的。如果我们查询(column_1,column_3)就只能用到column_1的索引了。我们不用太关心索引的先后顺序,什么意思呢?比如使用(column_1,column_2)和(column_2,column_1)的效果是一样的,数据库的查询优化器会自动帮助我们优化我们的sql,看哪个执行的效率最高,
最后才生成最后执行的sql。

为什么会有最左前缀呢?

​ 当使用b+树作为索引的存储数据结构时,当我们创建联合索引的时候,比如(column_1, column_2, column_3),b+树建立索引是从左到右来建立搜索树的,比如当我们来查询的时候WHERE column_1 = 1 AND column_2 = 2 AND column_3 = 3。b+树会先通过最左边的(建立索引的字段的左边的字段)字段,也就是column_1来确定下一步的查找对象,然后找到column_2,在通过column_2的索引找到column_3。所以(column_2,column_3)这样的查询命中不到索引了。因为最左前缀,一定是从最左边的字段开始依次在b+树的子节点查询,然后确定下一个查找的子节点的数据。所以我们(column_1)、(column_1,column_2)、(column_1,column_2,column_3)这三种查询条件是可以使用到索引的。

联合索引的存储结构

​ 定义联合索引(员工级别,员工姓名,员工出生年月),将联合索引按照索引顺序放入节点中,新插入节点时,先按照联合索引中的员工级别比较,如果相同会按照是员工姓名比较,如果员工级别和员工姓名都相同 最后是员工的出生年月比较。可以从图中从上到下,从左到右看,第一个B+树的节点 是通过联合索引的员工级别比较的,第二个节点是 员工级别相同,会按照员工姓名比较,第三个节点是 员工级别和员工姓名都相同,会按照员工出生年月比较。

img

联合索引字段的先后顺序

​ 我们定义多个字段的联合索引,会考虑到字段的先后顺序。那么字段的先后顺序真的会对查询的效率产生影响吗?比如上面的联合索引

index test_column_1_column_2_column_3_index on test (column_1, column_2, column_3);index test_column_1_column_2_column_3_index on test (column_2, column_1, column_3);在查询效率上有差别吗?我们试验下

写个函数批量插入下数据

CREATE PROCEDURE dowhile()
BEGINDECLARE v1 INT DEFAULT 20000000;WHILE v1 > 0 DOINSERT INTO test.test (column_1, column_2, column_3) VALUES (RAND() * 20000000, RAND() * 10000, RAND() * 20000000);SET v1 = v1 - 1;
END WHILE;
END;

​ 我们插入了20000000条数据,然后先设置索引(column_1, column_2, column_3)中column_1的数值范围为0到20000000,column_2的范围为0到10000。然后查询,看看这个索引的效率。数据量太大,插入的时间可能要好久。为什么插入20000000条呢,因为b+树可以高效存储的数据条数就是21902400,具体见下文。

​ 我们尝试下查询的效率

SELECT * FROM test WHERE column_1=19999834 AND  column_2=3601
> OK
> 时间: 0.001sEXPLAIN SELECT * FROM test WHERE column_1=19999834 AND  column_2=3601

img

我们看到索引的type为ref已经相当高效了。

​ type:这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一。
​ 结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。

​ 然后我们看下插入的效率

INSERT INTO test.test (column_1, column_2, column_3) VALUES (RAND() * 20000000, RAND() * 10000, RAND() * 20000000)
> Affected rows: 1
> 时间: 0.002s  

​ 更改索引的顺序

drop index test_column_1_column_2_column_3_index on test;create index test_column_2_column_1_column_3_indexon test (column_2, column_1, column_3); 

我们把column_2column_1的索引位置更换了一下,来比较联合索引的先后顺序对查询效率的影响。

SELECT * FROM test WHERE  column_2=3601 AND column_1=19999834
> OK
> 时间: 0.001sEXPLAIN SELECT * FROM test WHERE  column_2=3601 AND column_1=19999834  

img

发现更换了之后查询时间上没有什么出入,还和上个查询的时间一样,分析查询的效率一样很高。

再来看插入的效率

INSERT INTO test.test (column_1, column_2, column_3) VALUES (RAND() * 20000000, RAND() * 10000, RAND() * 20000000)
> Affected rows: 1
> 时间: 0.003s

​ 依然高效

​ 所以我们可以总结出来,联合索引中字段的先后顺序,在sql层面的执行效率,差别不大,是可以忽略的。分析上面索引的数据结构也是可以推断出来的,无非就是当建立联合索引,更换索引字段的先后顺序,匹配每个字段锁定的数据条数不一样,但是对最终的查询效率没有太大的影响。但是这个字段的顺序真的就不用考虑吗?不是的,我们知道有最左匹配原则,所以我们要考虑我们的业务,比如说我们的业务场景中有一个字段enterpriseId,这个字段在80%的查询场景中都会遇到,那么我们肯定首选将这个字段放在联合索引字段的第一个位置,这样就能保证查询的高效,能够命中我们建立的索引。

b+树可以存储的数据条数

​ b+树 正常的高度是(1~3)一个整型8b 指针占用6b,mysql页文件默认16K16k的数据可以存储16/14b=1170三层的数据大概就是1170*1170*16=21902400(千万条数据)所以千万级别的数据,对于建了索引的数据库查询的数据库也是很快的。

总结


对于联合索引,我们不能忽略它的最左匹配原则,即在检索数据时从联合索引的最左边开始匹配。对于创建联合索引时,我们要根据我们的具体的查询场景来定,联合索引字段的先后顺序,联合索引字段的先后顺序在sql层面上没有太大差别,但是结合查询的场景和最左匹配的原则,就能使一些查询的场景不能很好的命中索引,这点使我们是不能忽略的。

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

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

相关文章

php oracle 操作 sql语句中能不能添加数组_如何在PHP中使用Oracle数据库_php

在php3.0以上版本中,php内置了几乎目前所有的数据库处理函数,包括oracle;在本文中我们通过一个实例来介绍了如何使用这些函数来操作Oracle数据库。PHP提供了2大类API(应用程序接口)来操作Oracle数据库。一个是标准的Oracle处理函数(ORA) 另一个是Oracle …

mysql where过滤条件中and连接的两个条件的顺序不必和建立的联合索引的字段顺序一致_mysql and 顺序_mysql执行过程以及顺序

mysql中and的判断顺序 select * from a join b on 条件一 and 条件二条件一和二都是判断 id 字段, 条件一和条件二哪个先执行? 解析器会自动选择最优的流程执行的 这两个都是平级条件,理论上是没有先后顺序的! 没有顺序&#xff…

MySQL优化器_MySQL查询优化器

MySQL优化器 MySQL架构图 讲到MySQL,就绕不开他的架构图。MySQL是一个经典的C/S架构。服务器这边分两层:第一层是Server层,第二层是存储引擎。Server层处理主要的业务操作流程,但不关心具体的存储逻辑。存储逻辑由存储引擎层去…

MySQL性能优化(一)MySQL中SQL语句是如何执行的?

该篇章将开始整理MySQL的优化,不过开始之前,我们想了解清楚那就是MySQL是怎么执行的。 文章目录1.MySQL驱动2.应用系统数据库连接池3.MySQL数据库连接池4.SQL执行过程4.1.线程监听:监听网络请求中的SQL语句4.2.SQL接口:负责处理接…

2023_Spark_实验三十三:配置Standalone模式Spark3.4.2集群

实验目的:掌握Spark Standalone部署模式 实验方法:基于centos7部署Spark standalone模式集群 实验步骤: 一、下载spark软件 下载的时候下载与自己idea里对应版本的spark News | Apache Spark 选择任意一个下载即可 - spark 3.4.1 - spark …

MySQL性能优化(二)InnoDB之日志文件

文章目录1.MySQL日志记录文件1.1.回顾SQL语句的执行1.2.InnoDB内存结构:缓冲池1.3.记录日志:Undo和Redo1.3.1.Undo日志文件:记录数据修改前的值1.3.2.Redo日志文件:记录数据即将修改值1.3.3.Undo和Redo的区别(记录、前…

php正则检查QQ,PHP 正则匹配手机号的QQ号

//匹配手机号码//$mode /\d{3}-\d{8}|\d{4}-\d{7}|\d{11}/;//不匹配以-开头的手机号码//$mode /^((?!-).)*\d{3}-\d{8}|^((?!-).)*\d{4}-\d{7}|^((?!-).)*\d{11}/;//不匹配以 / 开头或结束的手机号码$mode /^((?!\/).)*\d{3}-\d{8}((?!\/).)*$|^((?!\/).)*\d{4}-\d{7}…

java获取单击内容,java – 单击菜单链接时,获取元素不是可点击的异常

我想点击菜单链接但没有运气.它总是显示异常 –Exception in thread “main” org.openqa.selenium.WebDriverException:unknown error: Element is not clickable at point (64, 64). Otherelement would receive the click: <div style”position: absolute; left:0px; to…

MySQL性能优化(三)Buffer Pool实现原理

文章目录1.回顾缓冲池 Buffer Pool2.配置Buffer Pool的大小3.Buffer Pool&#xff1a;数据结构3.1.磁盘数据结构&#xff1a;数据页3.2.缓冲池数据结构&#xff1a;数据页(缓存页)3.3.缓存页对应的描述信息4.Buffer Pool&#xff1a;初始化5.Buffer Pool&#xff1a;free链表6.…

MySQL性能优化(四)redo log实现原理

文章目录1.redo log的作用2.redo log的结构2.1.redo log 记录2.2.redo log block2.3.redo log buffer3.redo log buffer 刷盘1.redo log的作用 首先我们都知道&#xff0c;执行增删改SQL语句的时候&#xff0c;都是针对一个表中的某些数据去执行的&#xff0c;此时的话&#x…

MySQL性能优化(五)undo log是如何实现MVCC的?

之前我们最开始的几篇文章就讲过&#xff0c;你除了写redolog日志还必须要写undo log日志&#xff0c;这个undo log日志是至关重要的&#xff0c;没有他&#xff0c;你根本都没办法回滚事务&#xff01; 1.事务 1.1.多线程并发执行多个事务 对于我们的业务系统去访问数据库而…

Linux中Shell脚本--awk的用法

语法格式&#xff1a;awk [选项] ‘指令’ 操作文件 常用选项&#xff1a;-F 指定分隔符&#xff0c;分隔符用""引起来 -v&#xff1a;varvalue在awk程序开始之前指定一个值valu给变量var&#xff0c;这些变量值用于awk程序的BEGIN快 -f&#xff1a;后面跟一个保存…

linux下的shell脚本(基础)

Shell是一种脚本语言&#xff0c;那么&#xff0c;就必须有解释器来执行这些脚本&#xff0c;常见的脚本解释器有&#xff1a; bash&#xff1a;是Linux标准默认的shell。bash由Brian Fox和Chet Ramey共同完成&#xff0c;是BourneAgain Shell的缩写&#xff0c;内部命令一共有…

mysql rsync复制,mysql复制又同步

mysql复制再同步由于一个老旧系统没有使用LVM分区,导致mylvmbackup不能使用。为了重新全量同步数据库&#xff0c;发现rsync可以使用&#xff0c;并且锁住数据库的时间不长。1. 首先刷新数据库到文件flush tables with read lock;unlock tables;2. 执行rsync进行数据库同步/usr…

解决springboot中只支持get请求,无法支持post请求

解决springboot中只支持get请求&#xff0c;无法支持post请求 报错信息如下&#xff1a; 405 相关类如下&#xff1a; RestController RequestMapping public class HttpServiceController {Autowiredprivate HttpSecretReport httpSecretReport;Autowiredprivate HttpSecret…

mysql2005卸载步骤,二次安装mysql步骤

1.先将mysql服务停止&#xff0c;并关闭服务页面(否则后面报错&#xff1a;“指定的服务已经标记为删除”)&#xff1a;打开“任务管理器”可以找到服务页面2.在控制面板对mysql进行删除。找到并将其卸载&#xff0c;如果没有直接跳过3.在注册表中删除相关目录。(使用组合键&qu…

Spring Boot 默认数据源 HikariDataSource_Spring Boot 中使用 Hikari

Spring Boot 默认数据源 HikariDataSource springboot2.x之后&#xff0c;系统的默认数据源由原来的的org.apache.tomcat.jdbc.pool.DataSource更改为com.zaxxer.hikari.HikariDataSource。 HikariDataSource 号称 Java WEB 当前速度最快的数据源&#xff0c;相比于传统的 C3…

matlab取出等高线上的数据,在Python或MATLAB中从等高线图中提取数据

这是一个小型的Matlab脚本&#xff0c;可以完成这项工作(使用一些GUI&#xff0c;在图的斜角处读取guidlines)&#xff1a;%// Import the data:imdata importdata(your_picture_file);Gray rgb2gray(imdata.cdata);colorLim [-1 1]; %// this should be set manually%// Ge…

SpringBoot-默认数据源HikariDataSource对数据库操作及自动装配原理

默认数据源HikariDataSource对数据库操作 在创建项目时选择JDBC以及MySQL驱动&#xff0c;让SpringBoot自动装配所需组件 创建完成后默认的pom.xml文件如下 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.o…

matlab fgetl用法,Matlab fgetl strsplit 函数

函数功能&#xff1a;从文件中调用一行数据matlab中fgetl函数&#xff0c;并除去行末的换行符。语法格式&#xff1a;tline fgetl(fid)fid是通过fopen函数打开文件后得到的一个整型的文件标志。fgetl从这个文件中调用一行数据并丢弃其中的换行符。如果抓取成功tline容纳了调用…