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

MySQL索引特性(上)

目录

索引的重要

 案例

认识磁盘 

MySQL与存储

先来研究一下磁盘

 扇区

定位扇区

结论 

 磁盘随机访问与连续访问

MySQL与磁盘交互基本单位

建立共识

 索引的理解

建立测试表

 插入多条记录

局部性原理 


所有的MySQL的操作(增删查改)全部都是在MySQL当中的内存中进行的,MySQL在启动的时候会预先帮我们开辟一大块空间,开辟后在合适的时候把数据的操作体现在内存级,然后MySQL再把数据定期刷新到我们对应的外设也就是磁盘当中做持久化;索引也是如此 

索引的重要

索引:提高数据库的性能,索引是物美价廉的东西了。不用加内存,不用改程序,不用调sql,只要执行正确的 create index ,查询速度就可能提高成百上千倍。但是天下没有免费的午餐,查询速度的提高是以插入、更新、删除的速度为代价的,这些写操作,增加了大量的IO。所以它的价值,在于提高一个海量数据的检索速度(查是快了);    

常见索引分为:

1. 主键索引(primary key)

2. 唯一索引(unique)

3. 普通索引(index)

4. 全文索引(fulltext)--解决中子文索引问题。

 案例

先整一个海量表,在查询的时候,看看没有索引时有什么问题?

 向MySQL中导入mysql> source /home/wwz/index_data.sql

 导入后会在数据库中创建big_index库;use bit_insex;(因为数据量有点大所以根据机器导入时间不同)

mysql> show tables;//因为数据量好多所以不要selece *全部字段列否则要等待好久

mysql> select * from EMP limit 5;//可以列出部分少的

 查询员工编号为998877的员工

mysql> select * from EMP where empno=998877;

查询一条信息就用到5秒多,甚至有的机器因为数据量太大(亿级)直接killed服务(占资源太多了,os直接kill你了)

可以看到耗时5.75秒,这还是在本机一个人来操作,在实际项目中,如果放在公网中,假如同时有1000个人并发查询,那很可能就死机。

解决办法创建索引mysql> alter table EMP add index(empno);//加索引也需要时间

换一个员工编号,测试看看查询时间

mysql> select * from EMP where empno=1234567;//发现现在非常快(零点几秒)
由原来的线性遍历变为B+树的搜索当然快了;

认识磁盘 

MySQL与存储

MySQL 给用户提供存储服务,而存储的都是数据,数据在磁盘这个外设当中。磁盘是计算机中的一个机 械设备,相比于计算机其他电子元件,磁盘效率是比较低的,在加上IO本身的特征,可以知道,如何提 交效率,是 MySQL 的一个重要话题。

先来研究一下磁盘

 扇区

数据库文件,本质其实就是保存在磁盘的盘片当中。也就是上面的一个个小格子中,就是我们经常所说的扇区。当然,数据库文件很大,也很多,一定需要占据多个扇区。

从上图可以看出来,在半径方向上,距离圆心越近,扇区越小,距离圆心越远,扇区越大那么,所有扇区都是默认512字节吗?目前是的,我们也这样认为。因为保证一个扇区多大,是由比特位密度决定的。 不过最新的磁盘技术,已经慢慢的让扇区大小不同了,不过我们现在暂时不考虑。

我们在使用Linux,所看到的大部分目录或者文件,其实就是保存在硬盘当中的。(当然,有一些内存文 件系统,如: proc , sys 之类,我们不考虑)

数据库文件,本质其实就是保存在磁盘的盘片当中,就是一个一个的文件

 ll /var/lib/mysql    #我们目前MySQL中的文件


自己定义的数据库,里面有数据表

 所以最基本的,找到一个文件的全部,本质就是在磁盘找到所有保存文件的扇区。 而我们能够定位任何一个扇区,那么便能找到所有扇区,因为查找方式是一样的。

定位扇区

1. 柱面(磁道): 多盘磁盘,每盘都是双面,大小完全相等。那么同半径的磁道,整体上便构成了一个柱面

2. 每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的

3. 所以,我们只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号。即可在磁盘上定位所要访问的扇区。这种磁盘数据定位方式叫做CHS 。不过实际系统软件使用的并不是CHS (但是硬件是),而是LBA ,一种线性地址,可以想象成虚拟地址与物理地址。系统将 LBA 地址最后会转化成为 CHS ,交给磁盘去进行数据读取。不过,我们现在不关心转化细节,知道这个东西,让我们逻辑自洽起来即可。

结论 

我们现在已经能够在硬件层面定位,任何一个基本数据块了(扇区)。那么在系统软件上,就直接按照扇区 (512字节,部分4096字节),进行IO交互吗?不是

1. 如果操作系统直接使用硬件提供的数据大小进行交互,那么系统的IO代码,就和硬件强相关,换言之,如果硬件发生变化,系统必须跟着变化

2. 从目前来看,单次IO 512字节,还是太小了。IO单位小,意味着读取同样的数据内容,需要进行多次磁盘访问,会带来效率的降低。

3. 之前学习文件系统,就是在磁盘的基本结构下建立的,文件系统读取基本单位,就不是扇区,而是数据块。 故,系统读取磁盘,是以块为单位的,基本单位是 4KB 。

 磁盘随机访问与连续访问

随机访问:本次IO所给出的扇区地址和上次IO给出扇区地址不连续,这样的话磁头在两次IO操作之间需要作比较大的移动动作才能重新开始读/写数据。

连续访问:如果当次IO给出的扇区地址与上次IO结束的扇区地址是连续的,那磁头就能很快的开始这次IO操作,这样的多个IO操作称为连续访问。

因此尽管相邻的两次IO操作在同一时刻发出,但如果它们的请求的扇区地址相差很大的话也只能称为随机访问,而非连续访问。

磁盘是通过机械运动进行寻址的,随机访问不需要过多的定位,故效率比较高

MySQL与磁盘交互基本单位

首先MySQL是一款应用软件,他在系统角度就是应用进程,在网络层是应用服务所以都是在应用层的,可以想象成一种特殊的文件系统。它有着更高的IO场景,所以,为了提高基本的IO效率, MySQL进行IO的基本单位是16KB (后面统一使用 InnoDB 存储引擎讲解)

 mysql> show global status like 'innodb_page_size';
16384=1024*16;可以看到16KB大小(1KB=1024B)

也就是说,磁盘这个硬件设备的基本单位是512字节,而 MySQL InnoDB引擎使用16KB进行IO交互。 即MySQL 和磁盘进行数据交互的基本单位是16KB 。这个基本数据单元,在 MySQL这里叫做page(注意和系统的page区分)

建立共识

MySQL 中的数据文件,是以page(16KB)为单位保存在磁盘当中的。(在物理上MySQL存数据时以page为单位塞到文件里)

 MySQL 的 CURD(增删查改) 操作,都需要通过计算找到对应的插入位置,或者找到对应要修改或者查询的数据。

 而只要涉及计算,就需要CPU参与,而为了便于CPU参与,一定要能够先将数据移动到内存当中。(计算机结构所决定的)

 所以在特定时间内,数据一定是磁盘中有,内存中也有(相当于我把数据加载到内存里,当我改完了再刷新,也是以page为单位刷新覆盖历史的page数据)。后续操作完内存数据之后,以特定的刷新策略,刷新到磁盘。而这时,就涉及到磁盘和内存的数据交互,也就是IO了(其实也就是把MySQL的数据拷贝给os,单位是16KB,接下来让os强制的把16KB的数据或者整个缓冲区的数据持久化刷到磁盘里)。而此时IO的基本单位就是Page。

 为了更好的进行上面的操作, MySQL 服务器在内存中运行的时候,在服务器内部,就申请了被称为Buffer Pool 的的大内存空间,来进行各种缓存。其实就是很大的内存空间,来和磁盘数据进行IO交互。(MySQL是用c/c++写的,他开辟空间就是new或者malloc)

vim /etc/my.cnf          //可以看到默认128M大小

 为了更高的效率,一定要尽可能的减少系统和磁盘IO的次数;(就类比于我写100MB的数据,我一次把100MB的数据写到磁盘上和分100次每次1MB写到磁盘上来看,一次性的效率更高,因为只需要一次寻址找到磁盘当中的位置即可,如果100次的话可能进行100次寻址意味着磁盘盘片要转,磁头要摆)

 索引的理解

建立测试表

mysql> create table if not exists user(
    -> id int primary key,
    -> age int not null,
    -> name varchar(16) not null
    -> );

一定要添加主键,只有这样才会默认生成主键索引


默认就是InnoDB存储引擎

 插入多条记录

插入五条记录(随机插入的顺序)

查找发现我明明是无顺序插入的,最后是顺序插入


我们向一个具有主键的表中乱序插入数据,发现数据会自动排序;

 在MySQL内部(自己启动变成一个服务进程)一定需要并且会存在大量的page,也就决定了母三千里必须要将多个同时存在的page管理起来!需要先描述再组织;所以不要简单认为page是一个内存块(16KB大小),page内部也必须写入对用的管理信息!
struct page(

 struct page*prev,
 struct page * next,
 char buffer[num];
);----16KB                     
所以在MySQL里申请一个page就是new page;然后将所有的page用'链表'的形式管理起来(此链表非彼链表);-----在buffer pool内部,对MySQL中的page进行了一个建模!

为何MySQL和磁盘进行IO交互的时候,要采用Page的方案进行交互呢?用多少,加载多少不香吗? 其实多加载的就是预加载,可以有效减少IO次数;

如上面的5条记录,如果MySQL要查找id=2的记录,第一次加载id=1,第二次加载id=2,一次一条记录,那 么就需要2次IO。如果要找id=5,那么就需要5次IO。
但如果这5条(或者更多)都被保存在一个Page中(16KB,能保存很多记录),那么第一次IO查找id=2的时候,整个Page会被加载到MySQL的Buffer Pool中,这里完成了一次IO。但是往后如果在查找id=1,3,4,5 等,完全不需要进行IO了,而是直接在内存中进行了。所以,就在单Page里面,大大减少了IO的次数。

你怎么保证,用户一定下次找的数据,就在这个Page里面?我们不能严格保证,但是有很大概率,因为有局部性原理。 往往IO效率低下的最主要矛盾不是IO单次数据量的大小,而是IO的次数。

局部性原理 

计算机的局部性原理是指在程序执行过程中,访问的数据和指令往往集中在某些局部区域,而不是分散在整个存储空间中。这个原理有两个主要方面:
1. 时间局部性(Temporal Locality)如果程序中的某个数据项一旦被访问,那么在不久的将来它很可能被再次访问这意味着最近被使用过的内存位置很可能会被再次使用,因此计算机会将这些位置的数据保留在高速缓存中,以便更快地访问

2. 空间局部性(Spatial Locality)一旦某个数据被访问,与该数据附近的数据很可能也会被访问。例如,如果程序访问了一个数组元素,那么其相邻的元素也很可能在不久之后被访问。为了利用空间局部性,计算机系统通常会将邻近的数据项也加载到缓存中,以便减少访问延迟。
局部性原理是计算机系统中优化性能的重要依据,因为它允许系统在内存和处理器之间的数据传输更有效率,减少了存储器访问的时间和能量消耗。通过合理利用局部性,计算机可以更快速地执行程序,提高整体性能和响应速度。

相关文章:

  • 什么是死锁 , 以及产生的原因详细介绍
  • 1.6.丢弃法
  • 论文复现:Predictive Control of Networked Multiagent Systems via Cloud Computing
  • x264 编码器 CAVLC 熵编码源码分析
  • Alpine Linux 轻量级Linux 适合于 docker 容器镜像
  • 浏览器缓存:强缓存与协商缓存实现原理有哪些?
  • HTTPS请求头缺少HttpOnly和Secure属性解决方案
  • 微服务实战系列之玩转Docker(二)
  • redis基本类型和订阅
  • 数据结构之初始二叉树(2)
  • docker网络互联
  • 机器学习-20-基于交互式web应用框架streamlit的基础使用教程
  • 企业如何查看员工的上网时长和记录?如何查看公司局域网员工电脑的上网记录
  • uniapp 开发 App 对接官方更新功能
  • 【Android】基础—基本布局
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • Bootstrap JS插件Alert源码分析
  • co.js - 让异步代码同步化
  • download使用浅析
  • ES10 特性的完整指南
  • Fastjson的基本使用方法大全
  • iOS编译提示和导航提示
  • Javascript编码规范
  • Lucene解析 - 基本概念
  • Mac转Windows的拯救指南
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 区块链技术特点之去中心化特性
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 设计模式 开闭原则
  • 使用agvtool更改app version/build
  • 算法-插入排序
  • 算法---两个栈实现一个队列
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 异步
  • 用jQuery怎么做到前后端分离
  • 优秀架构师必须掌握的架构思维
  • 智能网联汽车信息安全
  • 400多位云计算专家和开发者,加入了同一个组织 ...
  • Hibernate主键生成策略及选择
  • 如何在招聘中考核.NET架构师
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • #前后端分离# 头条发布系统
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $L^p$ 调和函数恒为零
  • (07)Hive——窗口函数详解
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (南京观海微电子)——COF介绍
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转载)深入super,看Python如何解决钻石继承难题
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .net core Redis 使用有序集合实现延迟队列