为啥阿里巴巴不建议MySQL使用Text类型?

前言众所周知,MySQL广泛应用于互联网的OLTP(联机事务处理过程)业务系统中,在大厂开发规范中,经常会看到一条"不建议使用text大字段类型” 。
下面就从text类型的存储结构,引发的问题解释下为什么不建议使用text类型,以及Text改造的建议方法 。
背景写log表导致DML慢问题描述某歪有一个业务系统,使用RDS for MySQL 5.7的高可用版本,配置long_query_time=1s,添加慢查询告警,我第一反应就是某歪又乱点了 。
我通过监控看CPU, QPS,TPS等指标不是很高,最近刚好双十一全站都在做营销活动,用户量稍微有所增加 。某歪反馈有些原本不慢的接口变的很慢,影响了正常的业务,需要做一下troubleshooting 。
问题分析我从慢查询告警,可以看到有一些insert和update语句比较慢,同时告警时段的监控,发现IOPS很高,达到了70MB/s左右,由于RDS的CloundDBA功能不可用,又没有audit log功能,troubleshooting比较困难,硬着头皮只能分析binlog了 。
配置了max_binlog_size =512MB,在IOPS高的时段里,看下binlog的生成情况 。

为啥阿里巴巴不建议MySQL使用Text类型?

文章插图
 
需要分析为什么binlog写这么快,最有可能原因就是insert into request_log表上有text类型,request_log表结构如下(demo)
CREATE TABLE request_log (` `id bigint(20) NOT NULL AUTO_INCREMENT,` `log text,``created_at datetime NOT NULL,` `status tinyint(4) NOT NULL,` `method varchar(10) DEFAULT NULL,` `url varchar(50) DEFAULT NULL,` `update_at datetime DEFAULT NULL,` `running_time tinyint(4) DEFAULT '0',` `user_id bigint(20) DEFAULT NULL,` `type varchar(50) DEFAULT NULL,` `PRIMARY KEY (id)``) ENGINE=InnoDB AUTO_INCREMENT=4229611 DEFAULT CHARSET=utf8`分析binlog:
$ mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS mysql-bin.000539|egrep "insert into request_log"满屏幕都是看不清的内容,翻了半天没翻完 。
基本上已经确定是写入request_log的log字段引起的,导致binlog_cache频繁的flush,以及binlog过度切换,导致IOPS过高,影响了其他正常的DML操作 。
问题解决跟开发同学沟通后,计划在下一个版本修复这个问题,不再将request信息写入表中,写入到本地日志文件,通过filebeat抽取到es进行查询,如果只是为了查看日志也可以接入grayLog等日志工具,没必要写入数据库 。
文章最后我还会介绍几个MySQL 我踩过Text相关的坑,这介绍坑之前我先介绍下MySQLText类型 。
MySQL中的TextText类型text是一个能够存储大量的数据的大对象,有四种类型:TINYTEXT, TEXT, MEDIUMTEXT,LONGTEXT,不同类型存储的值范围不同,如下所示
Data TypeStorage RequiredTINYTEXTL + 1 bytes, where L < 2**8TEXTL + 2 bytes, where L < 2**16MEDIUMTEXTL + 3 bytes, where L < 2**24LONGTEXTL + 4 bytes, where L < 2**32
其中L表是text类型中存储的实际长度的字节数 。可以计算出TEXT类型最大存储长度2**16-1 = 65535 Bytes 。
InnoDB数据页Innodb数据页由以下7个部分组成:
内容占用大小说明File Header38Bytes数据文件头Page Header56 Bytes数据页头Infimun 和 Supermum Records
伪记录User Records
用户数据Free Space
空闲空间:内部是链表结构,记录被delete后,会加入到free_lru链表Page Dictionary
页数据字典:存储记录的相对位置记录,也称为Slot,内部是一个稀疏目录File Trailer8Bytes文件尾部:为了检测页是否已经完整个的写入磁盘
说明:File Trailer只有一个FiL_Page_end_lsn部分,占用8字节,前4字节代表该页的checksum值,最后4字节和File Header中的FIL_PAGE_LSN,一个页是否发生了Corrupt,是通过File Trailer部分进行检测,而该部分的检测会有一定的开销,用户可以通过参数innodb_checksums开启或关闭这个页完整性的检测 。
从MySQL 5.6开始默认的表存储引擎是InnoDB,它是面向ROW存储的,每个page(default page size = 16KB),存储的行记录也是有规定的,最多允许存储16K/2 - 200 = 7992行 。
InnoDB的行格式Innodb支持四种行格式:
行格式Compact存储特性增强的变长列存储支持大前缀索引支持压缩支持表空间类型REDUNDANTNoNoNoNosystem, file-per-table, generalCOMPACTYesNoNoNosystem, file-per-table, generalDYNAMICYesYesYesNosystem, file-per-table, generalCOMPRESSEDYesYesYesYesfile-per-table, general
由于Dynamic是Compact变异而来,结构大同而已,现在默认都是Dynamic格式;COMPRESSED主要是对表和索引数据进行压缩,一般适用于使用率低的归档,备份类的需求,主要介绍下REDUNDANT和COMPACT行格式 。
Redundant行格式这种格式为了兼容旧版本MySQL 。


推荐阅读