MySQL · 8.0版本更新 · 性能优化篇

摘要: 本文主要总结下MySQL在8.0版本和性能相关的一些改动,随着新的小版本的发布,本文将不断进行更新,直到正式GA。 已更新版本MySQL 8.0.0MySQL 8.0.0 WL#9387: InnoDB: Group purging of rows by table ID 这个问题最早是faceb...

本文主要总结下MySQL在8.0版本和性能相关的一些改动,随着新的小版本的发布,本文将不断进行更新,直到正式GA。

MySQL 8.0.0

WL#9387: InnoDB: Group purging of rows by table ID

这个问题最早是facebook的工程师Domas报的一个bug,InnoDB使用多线程来进行Undo Purge操作,但分配undo的策略不太合理,直接轮询分配。这意味着如果从一张表上删除大量数据,这N个purge线程可能产生大量的索引锁冲突(例如索引页合并及重组织)

在WL#9387中,在parse undo log时,通过table_id进行分组存储,在分发时确保同一个table id的记录被分配给同一个线程。(参考函数 trx_purge_attach_undo_recs)

当然这也意味着合理的不会产生冲突的单表操作, 无法利用到多线程purge了,也算是一个弊端。

WL#8423: InnoDB: Remove the buffer pool mutex

这个算是众望所归的改进了,由Percona贡献的补丁(bug#75534),主要是对InnoDB的buffer pool mutex这个大锁进行了拆分,降低锁冲突:

分配空闲block(buf_LRU_get_free_block):

  • 从free list获取: buf_pool_t::free_list_mutex
  • 从unzip_lru/lru上驱逐一个空闲page,需要buf_pool_t::LRU_list_mutex

批量扫描LRU(buf_do_LRU_batch): buf_pool_t::LRU_list_mutex

批量扫描FLUSH_LIST(buf_do_flush_list_batch): buf_pool_t::flush_list_mutex

脏页加入到flush_list(buf_flush_insert_into_flush_list): buf_pool_t::flush_list_mutex

脏页写回磁盘后,从flush list上移除(buf_flush_write_complete): buf_pool_t::flush_state_mutex/flush_list_mutex

从LRU上驱逐Page(buf_LRU_free_page):buf_pool_t::LRU_list_mutex, 及buf_pool_t::free_list_mutex(buf_LRU_block_free_non_file_page)

buf_flush_LRU_list_batch 使用mutex_enter_nowait 来获取block锁,如果获取失败,说明正被其他session占用,忽略该block.

有些变量的修改从通过buf_pool_t::mutex保护,修改成通过memory barrior来保护(os_rmb or os_wmb), 例如下面几个函数中均有体现:

btr_search_enable()

buf_resize_thread()

buf_get_withdraw_depth()

buf_LRU_get_free_block()

通过对锁的拆分,降低了全局大锁的竞争,提升了buffer pool的扩展性,这个特性其实在Percona Server中很多年前就有了, 但直到MySQL8.0版本才合并进来。

WL#7170: InnoDB buffer estimates for tables and indexes

主要是用于为优化器提供更准确的信息,即数据是存在与磁盘还是内存中, 这样优化器可以更准确的做出代价计算。

增加一个全局对象(buf_stat_per_index_t)来管理所有的索引页计数

为了避免引入新的全局锁开销,实现并使用一个lock-free的hash结构("include/ut0lock_free_hash.h)来存储索引信息,key值为索引id。(目前索引id具有唯一性,但不排除未来可能发生改变)。

增加计数:

1. Page刚从磁盘读入内存 (buf_page_io_complete --> buf_page_monitor)

2. 创建一个新的page (btr_page_create)

递减计数:Page从LRU上释放时进行递减(buf_LRU_block_remove_hashed)

增加新的information_schema.innodb_cached_indexs 打印每个索引在内存中的page个数,其结构如下:

mysql> show create table INNODB_CACHED_INDEXES\G

*************************** 1. row ***************************

Table: INNODB_CACHED_INDEXES

Create Table: CREATE TEMPORARY TABLE `INNODB_CACHED_INDEXES` (

`SPACE_ID` int(11) unsigned NOT NULL DEFAULT ‘0‘,

`INDEX_ID` bigint(21) unsigned NOT NULL DEFAULT ‘0‘,

`N_CACHED_PAGES` bigint(21) unsigned NOT NULL DEFAULT ‘0‘

) ENGINE=MEMORY DEFAULT CHARSET=utf8

1 row in set (0.00 sec)

### 和表名/索引名关联

SELECT

tables.name AS table_name,

indexes.name AS index_name,

cached.n_cached_pages AS n_cached_pages

FROM

information_schema.innodb_cached_indexes AS cached,

information_schema.innodb_sys_indexes AS indexes,

information_schema.innodb_sys_tables AS tables

WHERE

cached.index_id = indexes.index_id

AND

indexes.table_id = tables.table_id;

相关worklog: WL#7168: API for estimates for how much of table and index data that is in memory buffer

WL#9383: INNODB: ADD AN OPTION TO TURN OFF/ON DEADLOCK CHECKER

增加选项,可以动态关闭死锁检测,这对诸如热点更新这样的场景效果显著,之前已专门写了篇博客,感兴趣的自取。

Bug#77094

这个优化来自alisql的贡献,主要是优化了InnoDB Redo的扩展性问题,通过双buffer机制,允许在写日志到磁盘的同时,也允许进行mtr commit,具体参阅我写的这篇月报。

WL#7093: Optimizer provides InnoDB with a bigger buffer

为了减少对Btree的锁占用,InnoDB在读取数据时实际上是有一个小的缓存buffer。对于连续记录扫描,InnoDB在满足比较严格的条件时采用row cache的方式连续读取8条记录(并将记录格式转换成MySQL Format),存储在线程私有的row_prebuilt_t::fetch_cache中;这样一次寻路就可以获取多条记录,在server层处理完一条记录后,可以直接从cache中取数据而无需再次寻路,直到cache中数据取完,再进行下一轮。

在WL#7093中引入了新的接口,由于优化器可以估算可能读取的行数,因此可以提供给存储引擎一个更合适大小的row buffer来存储需要的数据。大批量的连续数据扫描的性能将受益于更大的record buffer。

Record buffer由优化器来自动决定是否开启,增加新的类Record_buffer进行管理, Record buffer的大小最大不超过128KB, 目前是hard code的,不可以配置。

判断及分配record buffer函数: set_record_buffer, 并通过新的API接口(handler::ha_set_record_buffer)传到引擎层

buffer本身是引擎无关的,在sever层分配,通过handler成员m_record_buffer传递到引擎层。

增加新的接口,判断是否支持Record buffer, 目前仅InnoDB支持,需要满足如下条件 (ref set_record_buffer):

  • access type 不是 ref, ref_or_null, index_merge, range, index 或者ALL
  • 不是临时表
  • 不是loose index scan
  • 进入InnoDB引擎层判断((row_prebuilt_t::can_prefetch_records))

return select_lock_type == LOCK_NONE // 只读查询

&& !m_no_prefetch   // 允许prefetch

&& !templ_contains_blob // 没有BLOB, TEXT, JSON, GEOMETRY这些大列

&& !templ_contains_fixed_point // 不是空间数据类型DATA_POINT

&& !clust_index_was_generated   // 需要用户定义的primary key 或者唯一索引(被隐式的用作Pk)

&& !used_in_HANDLER // 不是通过HANDLER访问的

&& !innodb_api // 不是通过类似innodb memcached访问的

&& template_type != ROW_MYSQL_DUMMY_TEMPLATE //不是check table

&& !in_fts_query; // 不是全文索引查询

在InnoDB中,当record buffer被配置时,就使用server层提供的record buffer,而不是row_prebuilt_t::fetch_cache

官方博客对此改进的介绍:http://mysqlserverteam.com/mysql-8-0-faster-batch-record-retrieval/

WL#9250: Split LOCK_thd_list and LOCK_thd_remove mutexes

该Worklog的目的是改进短连接场景下的性能,对thd list的操作可能导致比较高的锁竞争。

解决方案也比较传统,就是进行分区,将链表thd_list划分成多个数组,目前为8个分区,相应的锁LOCK_thd_remove和LOCK_thd_list锁也进行了分区。

转自:zhaiwx_yinfeng  云栖社区

时间: 2024-08-27 04:44:21

MySQL · 8.0版本更新 · 性能优化篇的相关文章

【朝花夕拾】Android性能优化篇之(五)Android虚拟机简介

前言 Android虚拟机的使用,使得android应用和Linux内核分离,这样做使得android系统更稳定可靠,比如程序中即使包含恶意代码,也不会直接影响系统文件:也提高了跨平台兼容性.在Android4.4以前的系统中,Android系统均采用Dalvik作为运行andorid程序的虚拟机,在android发展中具有举足轻重的地位,而Android 5.0及以后的系统使用ART虚拟机取代Dalvik,在性能上做了很大的优化.本文将对这两款虚拟机做一些介绍,主要内容如下: 一.什么是Dal

mysql分解连接的总结(来自于高性能MySQL以及自己网站性能优化)

许多高性能的站点都用了"分解连接"技术,也就是把单个多表连接查询改成多个但表查询,然后在程序中合并数据,比如: select a.*,b.* from A a join B b on a.id = b.id 可以替换为: select a.* from A; select b.* from B; 然后再把数据通过程序合并. 可能有些人认为这太浪费了,把一个查询语句变成两条查询语句或者更多的查询语句了,如果哪位猿类这样想了,那你就应该继续往下看了. 将连接查询重构为多表查询,总体有以下性

【朝花夕拾】Android性能优化篇之(一)序言及JVM篇

序言        笔者从事Anroid开发有些年头了,深知掌握Anroid性能优化方面的知识的必要性,这是一个程序员必须修炼的内功.在面试中,它是面试官的挚爱,在工作中,它是代码质量的拦路虎,其重要性可见一斑.在团队中,性能优化的工作又往往由经验丰富的老师傅来完成,可见要做好性能优化,绝不是一件容易的事情. 性能优化方面涉及的知识点比较广,有理论基础知识,也有实际操作技能,笔者将通过一系列的文章来进行整理,将主要包括Java虚拟机.内存分配.垃圾回收,android虚拟机.进程管理.内存优化.

最全 webpak4.0 打包性能优化清单

最全 webpak4.0 打包性能优化清单 webpack4.0如何进行打包优化? 无非是从两个角度进行优化,其一:优化打包速度,其二:优化打包体积,送你一份打包性能优化清单 1.使用loader的时候尽量指定exclude和inlucde来提高文件查找效率,避免不必要的查找,设置noParse参数 module: { noParse: /jquery/, // 不去解析jquery中的依赖 rules:[ { test: /\.js?$/, use: [ { loader: 'babel-lo

Mysql Join语法以及性能优化

引言 内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则保留其中部分.外左联结与外右联结的区别在于如果用A左联结B则A中所有记录都会保留在结果中,此时B中只有符合联结条件的记录,而右联结相反,这样也就不会混淆了. 一.Join语法概述 join 用于多表中字段之间的联系,语法如下: 代码如下: FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona table1:左表:table2:右表. JOIN 按照功能大致分为如下三类: IN

电商网站HTTPS实践之路(三)——性能优化篇

通过分析TLS握手过程的细节我们会发现HTTPS比HTTP会增加多个RTT网络传输时间,既增加了服务端开销,又拖慢了客户端响应时间.因此,性能优化是必不可少的工作.很多文章都集中在服务端的性能优化上,但对于电商行业而言,大部分的用户流量源于App,因此客户端的性能优化配合服务端才能使收益最大化. 1. HTTPS带来的负担 凡事都有两面性. 1.1 增加的传输延时 使用HTTPS传输增加的开销不仅仅是两次TLS握手的过程.优化性能首先要知己知彼.了解性能损耗在哪里,才能有针对性的进行部署. 对于

CSS 性能优化篇

 CSS 性能优化总结篇 1.命名与备注规范化 头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体佈局宽度:wrapper 左右中:left right center 登录条:loginbar 标志:logo 广告:banner 页面主体:main 热点:hot 新闻:news 下载:download 子导航:subnav 菜单:menu 子菜单:submenu 搜索:search 友情链接:fr

MySQL 8.0复制性能的提升(翻译)

What’s New With MySQL Replication in MySQL 8.0 MySQL复制从问世到现在已经经历了多个年头,它的稳定性和可靠性也在稳步的提高.这是一个不停进化的过程,由于MySQL的很多重要功能都是依赖于复制,所以复制的快速发展也是很容易理解的. 在MySQL的上一个版本当中,MySQL通过实现真正意义的并行复制将复制的性能提升到了一个新的层面,因为在MySQL 5.6的版本中,虽然号称是实现了并行复制,但是并行复制是schema级别的,即如果binlog row

【朝花夕拾】Android性能优化篇之(四)Apk打包

前言 APK,即Android Package,是将android程序和资源整合在一起,形成的一个.apk文件.相信所有的Android程序员是在IDE的帮助下,完成打包轻而易举,但对打包流程真正清楚的可能并不多.本章的内容比较简单,也是非常基础的内容,但是对理解android应用的结构却有很大的帮助.笔者写这篇文章的目的,一方面是为了弥补这方面的盲点,回顾和梳理apk打包方面的理论知识点:第二方面,是为了给后续写Android虚拟机知识做铺垫,进而去研究android的性能优化,这也是把这篇文