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

61 mysql 存储引擎之动态格式 MyISAM

前言

我们这里来看一下 MyISAM 存储引擎, 我们常见的那些 user, db, table_priv, proc 等等是基于 MyISAM

这是我们经常会提及的 两种持久化的存储引擎之一, 一是 MyISAM存储引擎, 另外一个是 InnoDB存储引擎 

我们这里来看一下 MyISAM 中动态长度的数据表的相关处理 

 

mysql.user 的表结构创建如下 

CREATE TABLE `user` (
  `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
  `User` char(32) COLLATE utf8_bin NOT NULL DEFAULT '',
  `Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `Create_tablespace_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '',
  `ssl_cipher` blob NOT NULL,
  `x509_issuer` blob NOT NULL,
  `x509_subject` blob NOT NULL,
  `max_questions` int(11) unsigned NOT NULL DEFAULT '0',
  `max_updates` int(11) unsigned NOT NULL DEFAULT '0',
  `max_connections` int(11) unsigned NOT NULL DEFAULT '0',
  `max_user_connections` int(11) unsigned NOT NULL DEFAULT '0',
  `plugin` char(64) COLLATE utf8_bin NOT NULL DEFAULT 'mysql_native_password',
  `authentication_string` text COLLATE utf8_bin,
  `password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  `password_last_changed` timestamp NULL DEFAULT NULL,
  `password_lifetime` smallint(5) unsigned DEFAULT NULL,
  `account_locked` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
  PRIMARY KEY (`Host`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'

 

 

基于 动态长度MyISAM 的数据表的数据输出 

执行 sql 如下 “select * from user;” 我们着重关注 User 为 “tz_test” 的这条用户记录 

从 MYD 中读取 block_header 相关信息, 然后 mi_get_block_info 是从 block_header 中解析数据到 block_info

如果当前 block 是已经被删除掉的 block, 迭代下一个 block

d8ac549328addb00e97281a075ab2a94.png

 

然后是 上面 mi_read_cache 读取了 sizeof(block_info.header) 20 个字节的数据, 但是前面 block_header 可能仅仅只占用了 一部分字节

block_header 之后的数据, 也是数据部分, 需要将这部分数据填充到结果 buffer 中 

“if (block_of_record == 0)” 的处理是在更新当前记录的 left_len 表示的是当前记录的总共长度, 以及更新输出目标缓冲 

比如这里说明了当前记录 总共长度为 116, 然后 block_header 长度为 4

上面 mi_read_cache 中读取的, 还有 16 个字节属于记录的数据部分 

9f088b1e5806351e52024f81021b40ce.png

 

然后就是 读取当前 block 的剩余的数据部分了, 然后内容输出到 输出缓冲区中

然后更新 left_len, 如果 left_len 表示当前记录还是有 block, 需要继续 向后遍历

c424186f6b60a20d0f8e6b1e7c4d6730.png

 

动态长度的 MyISAM 这边的数据记录组织是以 block 为单位的 

一个 或者 多个 block 组成一个 record 

 

 

基于 动态长度MyISAM 的数据表的数据行

数据行 的信息如下

INSERT INTO `mysql`.`user`(`Host`, `User`, `Select_priv`, `Insert_priv`, `Update_priv`, `Delete_priv`, `Create_priv`, `Drop_priv`, `Reload_priv`, `Shutdown_priv`, `Process_priv`, `File_priv`, `Grant_priv`, `References_priv`, `Index_priv`, `Alter_priv`, `Show_db_priv`, `Super_priv`, `Create_tmp_table_priv`, `Lock_tables_priv`, `Execute_priv`, `Repl_slave_priv`, `Repl_client_priv`, `Create_view_priv`, `Show_view_priv`, `Create_routine_priv`, `Alter_routine_priv`, `Create_user_priv`, `Event_priv`, `Trigger_priv`, `Create_tablespace_priv`, `ssl_type`, `ssl_cipher`, `x509_issuer`, `x509_subject`, `max_questions`, `max_updates`, `max_connections`, `max_user_connections`, `plugin`, `authentication_string`, `password_expired`, `password_last_changed`, `password_lifetime`, `account_locked`) VALUES ('%', 'tz_test', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', '', '', '', '', 0, 0, 0, 0, 'mysql_native_password', '*3F42368149F6125F466E32249394BC6D395E6D4A', 'N', '2023-08-06 05:01:16', NULL, 'N');

22378a19c6aef1ef68ff28444a2b9dfe.png

 

 

 基于 动态长度MyISAM 的数据表的数据录入

执行 sql 如下 

create user 'tz_test_001'@'%' identified by 'tz_test_001';
grant select on tz_test_001.tz_test_02 to 'tz_test_001'@'%';
drop user 'tz_test_001';

新增 “tz_test_001” 对应的用户, 记录长度为 118

mi_find_writepos 是查询可用的节点, 如果不是必须在文件末尾增加数据, 可以吧删除的节点使用起来 

否则 在末尾创建 block, 来存放当前记录 

然后 就是写入 目标记录, 或者 目标记录的一部分

如果当前 block 写不完 record 的所有信息, 则进入下一个循环 mi_find_writepos + mi_write_part_record

089200f4fcb85e1c70d0a908ed47c798.png

 

查询可用空间方式如下, 如果是 不必须在末尾添加数据 则可以使用 删除链表的各个 block 

否则 在文件末尾新建 block

6a79914ce111869194d450c5d2a360db.png

 

写出 block 方式如下 

根据各种情况封装 block_header, 这里是 tz_test_001 走的如下展开的 block 的处理 

接着是写出 record 中的数据到 当前 block

4d680ee6e16688d12773b5a13963e949.png

 

将 block_header 写入 record – head_length

将当前 block 可以容纳的数据写入 record

然后将当前 block 的数据写入到 MYD 中文件对应的当前 block 的地方 

32c8584a5f62a340a1e8e96b1fbf9b87.png

 

 

基于 动态长度MyISAM 的数据表的数据删除  

遍历当前记录的 block 列表, 依次将 block 添加到 info->s->state->delink 的删除链表中 

将 “block_header[0] = 0;” 表示的就是标记删除当前 block 

cf3d0d8d0746c09b8edfab1927dd1dfb.png

 

 

 

 

 


http://www.kler.cn/news/364888.html

相关文章:

  • GD32学习知识点累计
  • Discuz发布原创AI帖子内容生成:起尔 | AI原创帖子内容生成插件开发定制
  • Elasticsearch基本使用及介绍
  • 4K双模显示器7款评测报告
  • Failed to fetch dynamically imported module
  • SLAM|1. 相机投影及相机畸变
  • react18中的计算属性及useMemo的性能优化技巧
  • 如何利用 KPaaS 低代码及 CI/CD 优化企业业务集成与流程
  • 企业架构与业务流程管理之间的关系
  • 国产数据库的蓝海在哪?
  • 手动将python的flask程序打包成exe在windows上执行
  • Zabbix企业级分布式监控环境部署
  • Solidworks 选项卡不显示草图、焊件等选项
  • Docker 搭建mysql
  • 15.6 JDBC数据库编程6——可滚动和可更新的ResultSet
  • FFMPEG录屏(20)--- 枚举macOS下的窗口和屏幕列表,并获取名称缩略图等信息
  • OpenCV系列教程六:信用卡数字识别、人脸检测、车牌/答题卡识别、OCR
  • 利用飞腾派进行OpenCV开发
  • 【C++修炼】初识C++:命名空间、缺省参数、函数重载、引用、内联函数、指针空值
  • java编译[WARNING]告警处理
  • OpenCV KeyPoint与描述子编解码
  • 搭建你的第一个Spring Cloud Alibaba微服务
  • Java | Leetcode Java题解之第492题构造矩形
  • 论文引用收录证明有什么用?
  • vue2之混入(mixin)
  • python的接口自动化的测试与实现java监测jsp源代码Mysql