《MySQL技术内幕InnoDB存储引擎》第01章 MySQL体系结构和存储引擎

1.1 定义数据库和实例 mysql启动 mysql会读取配置然后进行启动,若没有配置则按默认设置进行启动。配置的读取顺序为: /etc/my.cnf, /etc/mysql/my.cnf, ~/.my.cnf ,多个配置中设置了同一参数,则后者覆盖前者。 更多详细内容请阅读4.2.2.2 Using Option Files 配置文件中的datadir参数 这个参数组合定了数据库所在的路径,linux下默认为/usr/local/mysql/data, 其实它只是一个指向/opt/mysql_data/的链接 1.2 MySQL体系结构 MySQL由以下几部分组成: 连接池组件 管理服务和工具组件 SQL接口组件 查询分析器组件 优化器组件 cache组件 插件式存储引擎 物理文件 重要特点: 插件式的表存储引擎 需要注意的是: 存储引擎是基于表的, 而不是数据库的。 1.3 MySQL存储引擎 InnoDB InnoDB存储引擎设计目标为面向在线事务处理( OLTP)的应用 支持事务,行锁设计,支持外键,支持非锁定读(默认读操作不加锁) 通过使用多版本并发控制(MVCC)来获得高并发性 实现了SQL标准的4种隔离级别,默认为REPEATABLE级别 使用next-key这种策略避免幻读 提供插入缓冲(insert buffer),二次写(double write),自适应哈希索引(adaptive hash index),预读(read ahead)等高性能和高可用的功能 采用聚集(clustered)的方式对表中的数据进行存储。每张表的存储都按主键的顺序进行存放;如果没有显示的定义主键,InnoDB会为每行生成一个ROWID,并以此作为主键 省略以下存储引擎的笔记 MyISAM NDB Memory Archive Federated Maria 部分笔记参考对应的xmind文件 1.4 各个存储引擎之间的对比 1.5 连接到MySQL 与MySQL的连接,本质上是进程间同信,参考linux进程间通信的相关知识 通过TCP/IP 通过命名管道和共享内存 通过UNIX域套接字

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《MySQL技术内幕InnoDB存储引擎》第02章 InnoDB存储引擎

2.1 InnoDB存储引擎概述 支持ACID事务,特点是行锁设计 支持MVCC 支持外键 提供一次性非锁定读 2.2 InnoDB存储引擎的版本 2.3 InnoDB体系结构 后台线程总览 主要作用是负责刷新内存池中的数据,保证缓冲池中的数据是最近的数据 将已修改的数据文件刷新到磁盘文件 保证异常发生时InnoDB能恢复到正常状态 内存池总览 维护所有进程/线程需要访问的多个内部数据结构 缓存磁盘上的数据,方便快速的读取,同时在对磁盘文件的数据修改之前在这里缓存 重做日志(redo log)缓冲 2.3.1 后台线程(建议先看2.3.2) 后台线程由Master Thread,I/O Thread, Purge Thread, Page Cleaner Thread 组成,详细如下 2.3.1.1 Master Thread 主要负责将缓冲池中的数据异步刷新到磁盘,保持数据的一致性,包括脏页的刷新、合并插入缓冲、UNDO页的回收等。 Master Thread总体上分两类操作,分别是每秒进行的,以及每10秒进行的。 每秒进行的操作: 日志缓冲刷新到磁盘,即使这个事务还没有提交 合并插入缓冲(可能发生)当前1秒内发生IO次数小于5则合并 当buf_get_modified_ratio_pct > innodb_max_dirty_pages时,刷新脏页到磁盘(可能发生,至多100个脏页) 如果当前没有用户活动,则切换到background loop 每10秒进行的操作: 刷新100个脏页到磁盘(可能) 合并之多5个插入缓冲(总是) 将日志缓冲刷新到磁盘 删除无用的undo页 刷新100个或者10个脏页到磁盘 Master Thread具体分为loop, background loop,flush loop, suspend loop四个循环 2.3.1.1.1 InnoDB 1.0.x版本之前 Master Thread的伪代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 void master_thread(){ goto loop; loop: for(int i=0; i<10; ++i){ thread_sleep(1); flush_log_buffer_to_disk(); if(last_one_second_io < 5){ merge_at_most_5_insert_buffer(); } if(buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct){ flush_100_dirty_page(); } if(no_user_activity){ goto background_loop; } } if(last_ten_second_io < 200){ flush_100_dirty_page(); } merge_at_most_5_insert_buffer(); flush_log_buffer_to_disk(); full_purge(); if(buf_get_modified_ratio_pct > 0....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第01章-MySQL架构与历史

1.1 MySQL 逻辑架构 1.1.1 1.1.2 优化与执行 MySQL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的读取顺序、选择合适的索引等。 用户可以通过特殊的关键字提示(hint)优化器,影响它的决策过程。 可以请求优化器解释(explain)优化过程的各个因素,使用户可以知道服务器是如何进行优化决策的,并提供一个参考基准,便于用户重构查询和schema、修改相关配置。 对于select语句,在解析查询之前,服务器会先检查查询缓存(Query Cache),如果能找到对应查询,服务器就不必再执行查询解析、优化和执行整个过程。 1.2 并发控制 MySQL在两个层面的并发控制:服务器层与存储引擎层 1.2.1 读写锁 1.2.2 锁粒度 读写锁 锁粒度 1.3 事务 A(atomicity)C(consistency)I(isolation)D(durability) 1.3.1 隔离级别 READ UNCOMMITTED (未提交读) READ COMMITTED (读提交) REPEATABLE READ (可重复读) SERIALIZABLE (可串行化) 1.3.2 死锁 数据库实现了各种死锁检测和死锁超时机制 InnoDB目前处理死锁的方法是:将持有最少行级排他锁的事务进行回滚。 死锁发生后,只有部分或完全回滚其中一个事务,才能打破死锁。对于事务型的系统,这是无法避免的,所有应用程序在设计时必须考虑如何处理死锁。 1.3.3 事务日志 事务日志可以帮助提高事务的效率,不必每次都将修改的数据本身持久化到磁盘。 事务日志采用的是追加的方式,写日志操作是磁盘上一小块区域的顺序I/O,比每次修改都写回数据库对应磁盘位置可能导致的随机I/O要快 事务日志持久化后,可以慢慢地刷回磁盘。 以上这种设计,被称为预写式日志 (Write-Ahead Logging) 隐式和显式锁定 InnoDb采用的是两段锁协议(two-phase locking protocol) 事务执行的过程中,随时都可以锁定,但是只有在commit和rollback时同时释放。 InnoDB支持显示锁定:(非标准SQL) 1 2 select....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第02章-MySQL基准测试

2.1 为什么需要基准测试 2.2 基准测试的策略 2.2.1 测试何种指标 吞吐量:单位时间内的事务处理数 (每秒事务数TPS) 响应时间或延迟:通常使用百分比响应时间来代替最大响应时间 并发性: 可扩展性: 2.3 基准测试方法 错误的基准测试方法: 使用真实数据的子集而不是全集 使用错误的数据分布 使用不真实的分布参数 在多用户场景中,只做单用户测试 在单服务器上测试分布式应用 与真实用户行为不匹配 反复执行同一个查询 没有检查错误 忽略了系统预热(warm up)的过程 使用默认的服务器配置 测试时间太短 2.3.2 基准测试应该运行多长时间 一个常见的错误的测试方式是,只执行一系列短期的测试,比如60秒。 2.3.3 获取系统性能和状态 2.3.4 获取准确的测试结果 2.3.5 运行基准测试并分析结果 2.4 基准测试工具 2.4.1 集成式测试工具 2.4.2 单组件式测试工具 2.5 基准测试案例 2.5.3 sysbench: oltp、fileio

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第03章-服务器性能剖析

3.1 3.1.1 通过性能剖析进行优化 - 两种性能剖析:基于执行时间的分析和基于等待的分析 3.1.2 理解性能剖析 - 值得优化的查询 - 异常情况 - 未知的未知: - 被隐藏的细节 3.2 对应用程序进行性能剖析 3.3 剖析MySQL查询 3.3.1 剖析服务器负载 慢查询日志 分析查询日志 以一些典型的时间窗口如业务高峰期的一个小时内记录查询 pt-query-digest 分析MySQL查询日志的工具 3.3.2 剖析单条查询 show profile 查看时间消耗 直接查询information_schema中对应的表,可以排序 使用show status:返回一些计数器,其中有全局级的、会话级的 使用慢查询日志 使用performance schema 3.3.3 使用性能剖析 3.4 诊断间歇性问题 3.4.1 单条查询问题还是服务器问题 较高频率的执行show global status ,如1秒一次 show processlist,观察是否有大量线程处于不正常的状态或者其他不正常的特征。 使用查询日志 3.4.2 捕获诊断数据 3.4.3 一个诊断案例 3....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第04章-Schema与数据类型优化

4.1 选择优化的数据类型 更小的通常更好: 应该尽量的使用可以正确存储数据的最小数据类型。更小的数据类型通常更快,占用更少的磁盘、内存、CPU缓存,处理时需要的CPU周期更少 简单就好:简单数据类型的操作通常需要更少的CPU周期。例如整型比字符操作代价更低 尽量避免NULL: 通常情况下最好指定列为NOT NULL。因为如果查询中包含可谓NULL的列,对MySQL来说更难优化优化,NULL使得索引、索引统计和值比较都更复杂 将NULL改为NOT NULL带来的性能提升较小 4.1.1 整数类型 TINYINT:8 bit SMALLINT:16 bit MEDIUMINT:24 bit INT:32 bit BIGINT:64 bit 以上全部都支持unsigned MySQL可以为整数类型指定宽度,例如INT(11),但对存储和计算来说,INT(1)和INT(20)是相同的。这么做只是规定了一些交互工具(例如MySQL命令行客户端)用来显示字符的个数 4.1.2 实数类型 float(4 Byte)和double(8 Byte)类型支持使用标准的浮点运算进行近似计算 decimal类型用于存储精确的小数 浮点和decimal类型都可以指定精度 4.1.3 字符串类型 字符串长度定义不是字节数,而是字符数 varchar: 用于存储可变长字符串,它比定长类型更节省空间,因为它仅使用必要空间。(一种情况例外:表使用ROW_FORMAT=FIXED创建,每一行都会使用定长存储) 使用1个或2个字节记录字符串长度。例如,varchar(10)需要11 byte, varchar(1000) 需要1002 byte 以下情况使用varchar是合适的:字符串列的最大长度比平均长度要大很多,列的更新很少,所以碎片不是问题。 InnoDB可以把过长的varchar存储为blob类型 char char类型是定长的,MySQL会删除所有的末尾空格,char适合存储很短的字符串,或者所有值都接近同一个长度。 对于经常变更的数据,char也比varchar要好,因为定长的cahr类型不容易产生碎片。 对于非常短的列,char相比与varchar,没有记录长度的1 byte开销,效率更高。 BLOB和TEXT类型 BLOB和TEXT都是为了存储大数据而设计的字符串数据类型,分别采用二进制和字符方式存储 BLOB存储的是二进制数据,没有排序规则或字符集 TEXT有字符集和排序规则 因为Memory引擎不支持BLOB和TEXT类型,如果查询使用了这两种类型,并且需要使用隐式临时表,将不得不使用MyISAM磁盘临时表(新版本还是?)。解决方法是,使用substring()转换为字符串 TEXT: TINYTEXT SMALLTEXT (TEXT的同义词) TEXT MEDIUMTEXT LONGTEXT BLOB:...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第05章-创建高性能索引

intro 索引优化通常是优化查询性能的最有效手段 5.1 索引的基础 5.1.1 索引的类型 B-Tree 索引 “B-Tree”这么叫的原因是MySQL在CREATE TABLE和其他语句中也使用该关键字 存储引擎以不同的方式使用B-Tree,例如MyISAM使用前缀压缩技术使得索引更小,但InnoDB则按照原数据格式进行存储;MyISAM索引通过数据的物理位置引用索引的行,而InnoDB则根据主键引用被索引的行 B-Tree 对索引是顺序组织的,很适合查找范围数据。 索引对多个值进行排序的依据是CREATE TABLE语句中定义索引时列的顺序。 索引中的列的顺序十分重要 索引生效的场景: 全值匹配(使用索引中所有列进行匹配) 匹配最左前缀(只使用索引的前几列) 匹配列前缀(每列支持前缀匹配) 匹配范围值 精确匹配某一列并范围匹配另外一列 只访问索引的查询 B-Tree索引的限制: 如果不是按照索引的最左列开始查询,无法使用索引 不能跳过索引中的列 如果查询中某个列的范围查询,则其右边所有的列都无法使用索引优化查找 哈希索引 只有精确匹配索引所有列的查询才有效 Memory引擎显式支持哈希索引 哈希索引只包含索引值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。 不支持排序 不支持部分索引列匹配查找,只支持等值比较查询 如果哈希冲突很多,一些索引的维护操作的代价也会很高,查找也会变慢 空间数据索引(R-Tree) 全文索引 其他索引类型 5.2 索引的优点 索引大大减少了服务器需要扫描的数据量 索引可以帮助服务器避免排序和临时表 索引可以将随机I/O变为顺序I/O 5.3 高性能索引策略 5.3.1 独立的列:索引列不能是表达式的一部分 5.3.2 前缀索引和索引选择性:决定合适的前缀长度 5.3.3 多列索引 5.3.4 选择合适的索引列顺序 通常将选择性最高的列放在前面 同时可能需要根据那些运行频率最高的查询来调整索引列的顺序 总之,让整体执行的次数最少 5.3.5 聚簇索引 优点: 可以把相关数据保存在一起 数据访问更快 使用覆盖索引扫描的查询可以直接使用页节点中的主键值 缺点:...

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀

《高性能MySQL》第06章-查询性能优化

第06章-查询性能优化 设计合理的查询 6.1 查询为什么会慢? 6.2 慢查询基础:优化数据访问 6.2.1 是否数据库请求了不需要的数据 查询了不需要的记录 多表关联时返回全部列 总是取出全部列 重复查询相同的数据 6.2.2 是否在扫描额外的记录 衡量指标: 响应时间 扫描的行数、访问类型 返回的行数 如果发现查询需要扫描大量的数据但是只返回少数的行,那么常见的优化技巧: 使用覆盖索引(无需回表) 改变库表结构。例如使用单独的汇总表 重写这个复杂的查询 6.3 重构查询的方式 6.3.1 一个复杂查询还是多个简单查询 6.3.2 切分查询 6.3.3 分解关联查询 (1)让缓存的效率更高 (2)减少锁的竞争 (3)查询效率可能提升 (4)可以减少冗余记录的查询 (5)在应用层做关联,更容易对数据库进行拆分,更容易做到高性能和可扩展 (6)相当于在应用层做了哈希关联 6.4 查询执行的基础 6.4.1 MySQL 客户端 / 服务器通信协议 MySQL客户端与服务器之间的通信协议是“半双工”的(?) 缺点:无法进行流量控制 max_allowed_packet 查询状态: show full processlist; Sleep Query Locked Analyzing and statistics Copying to tmp table [on disk] Sorting Result Sending Data 6....

created: 2023-04-04  |  updated: 2023-04-04  |  阿秀