原文 https://yq.aliyun.com/articles/9072

最近看到一些老应用,在表结构的设计上使用了text或者blob的字段;其中一个应用,对blob字段的依赖非常的严重,查询和更新的频率也是非常的高,单表的存储空间已经达到了近100G,这个时候,应用其实已经被数据库绑死了,任何应用或者查询逻辑的变更几乎成为不可能;

为了清楚大字段对性能的影响,我们必须要知道innodb存储引擎在底层对行的处理方式:

知识点一:在5.1中,innodb存储引擎的默认的行格式为compact(redundant为兼容以前的版本),对于blob,text,varchar(8099)这样的大字段,innodb只会存放前768字节在数据页中,而剩余的数据则会存储在溢出段中(发生溢出情况的时候适用);

知识点二:innodb的块大小默认为16kb,由于innodb存储引擎表为索引组织表,树底层的叶子节点为一双向链表,因此每个页中至少应该有两行记录,这就决定了innodb在存储一行数据的时候不能够超过8k(8098字节);

知识点三:使用了blob数据类型,是不是一定就会存放在溢出段中?通常我们认为blob,clob这类的大对象的存储会把数据存放在数据页之外,其实不然,关键点还是要看一个page中到底能否存放两行数据,blob可以完全存放在数据页中(单行长度没有超过8098字节),而varchar类型的也有可能存放在溢出页中(单行长度超过8098字节,前768字节存放在数据页中);

知识点四:5.1中的innodb_plugin引入了新的文件格式:barracuda(将compact和redundant合称为antelope),该文件格式拥有新的两种行格式:compressed和dynamic,两种格式对blob字段采用完全溢出的方式,数据页中只存放20字节,其余的都存放在溢出段中:

知识点五:mysql在操作数据的时候,以page为单位,不管是更新,插入,删除一行数据,都需要将那行数据所在的page读到内存中,然后在进行操作,这样就存在一个命中率的问题,如果一个page中能够相对的存放足够多的行,那么命中率就会相对高一些,性能就会有提升;

有了上面的知识点,我们一起看看该应用的特点,表结构:

CREATE TABLE `xx_msg` (

`col_user` VARCHAR(64) NOT NULL,

`col_smallint` SMALLINT(6) NOT NULL,

`col_lob` longblob,

`gmt_create` datetime DEFAULT NULL,

`gmt_modified` datetime DEFAULT NULL,

PRIMARY KEY (`xxx`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk

col_lob为blob字段,用于存放该用户的所有的消息,其平均长度在2.4kb左右,该表中其他剩余的字段则是非常的小,大致在60字节左右

SELECT avg(LENGTH(col_clob)) FROM (SELECT * fromxxx_msg LIMIT 30000)a;

|         2473.8472 |

该表的应用场景包括:

1) select col_user ,col_smallint,DATE_FORMAT(gmt_modified,’%Y-%m-%d’) from xx_msg;

2) update xx_msg set gmt_modified=’2012-03-31 23:16:30′,col_smallint=1,col_lob=’xxx’ where col_user=’xxx’;

3) select col_smallint from xx_msg where user=’xxx’;

可以看到由于单行的平均长度(2.5k)还远小于一个innodb page的size(16k)(当然也有存在超过8k的行),也就是知识点三中提到的,blob并不会存放到溢出段中,而是存放到数据段中去,innodb能够将一行的所有列(包括longlob)存储在数据页中:

在知识点五中,mysql的io以page为单位,因此不必要的数据(大字段)也会随着需要操作的数据一同被读取到内存中来,这样带来的问题由于大字段会占用较大的内存(相比其他小字段),使得内存利用率较差,造成更多的随机读取。

从上面的分析来看,我们已经看到性能的瓶颈在于由于大字段存放在数据页中,造成了内存利用较差,带来过多的随机读,那怎么来优化掉这个大字段的影响:

一.压缩:

在知识点四中,innodb提供了barracuda文件格式,将大字段完全存放在溢出段中,数据段中只存放20个字节,这样就大大的减小了数据页的空间占用,使得一个数据页能够存放更多的数据行,也就提高了内存的命中率(对于本实例,大多数行的长度并没有超过8k,所以优化的幅度有限);如果对溢出段的数据进行压缩,那么在空间使用上也会大大的降低,具体的的压缩比率可以设置key_blok_size来实现。

二.拆分:

将主表拆分为一对一的两个关联表:

CREATE TABLE `xx_msg` (

`col_user` VARCHAR(64) NOT NULL,

`col_smallint` SMALLINT(6) NOT NULL,

`gmt_create` datetime DEFAULT NULL,

`gmt_modified` datetime DEFAULT NULL,

PRIMARY KEY (`xxx`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

CREATE TABLE `xx_msg_lob` (

`col_user` VARCHAR(64) NOT NULL,

`col_lob` longblob,

PRIMARY KEY (`xxx`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk

xx_msg表由于将大字段单独放到另外一张表后,单行长度变的非常的小,page的行密度相比原来的表大很多,这样就能够缓存足够多的行,表上的多个select由于buffer pool的高命中率而受益;应用程序需要额外维护的是一张大字段的子表;

三.覆盖索引:

在上面的两个查询当中,都是查询表中的小字段,由于老的方案需要全表或者根据主键来定位表中的数据,但是还是以page为单位进行操作,blob字段存在还是会导致buffer pool命中率的下降,如果通过覆盖索引来优化上面的两个查询,索引和原表结构分开,从访问密度较小的数据页改为访问密度很大的索引页,随机io转换为顺序io,同时内存命中率大大提升;额外的开销为数据库多维护一个索引的代价;

alter table xx_msg add index ind_msg(col_user ,col_smallint,gmt_modified);

对于查询一,原来的执行计划为走全表扫描,现在通过全索引扫描来完成查询;

对于查询二,原来的执行计划为走主键PK来定位数据,现在该走覆盖索引ind_msg完成查询;

注意上面的两个查询为了稳固执行计划,需要在sql执行中加入hint提示符来强制sql通过索引来完成查询;

总结:上面三种思路来优化大字段,其核心思想还是让单个page能够存放足够多的行,不断的提示内存的命中率,尽管方法不同,但条条大路通罗马,从数据库底层存储的原理出发,能够更深刻的优化数据库,扬长避短,达到意想不到的效果。

Mysql大字段blob返回是数字_innodb使用大字段text,blob的一些优化建议(转)相关推荐

  1. mysql倒叙varchar类型的数字_MySql遇到varchar字段数字字符串排序问题

    项目中遇到的问题,一个笔试试卷成绩查询最高分和最低分,简单的对分数字段排序,一直是正常的. 出bug了 就这个简单的功能,突然有一天,客户发现很奇怪的是最高分比最低分还低. 这明显是有问题的: 数据库 ...

  2. mysql批量insert bug_MySQL Bug insert into on duplicate key update 语法更新 text blob 大字段导致 MySQL crash...

    1. 背景 业务执行 SQL 导致 MySQL 进程 Crash,做故障切换后,新的主库又 Crash 了.查看 MySQL 错误日志,发现多次 Crash 时的堆栈相同,如下: Thread poi ...

  3. mysql存储过程更新数据后返回一个字段_史上最全存储引擎、索引使用及SQL优化的实践...

    整个MySQL Server由以下组成 : Connection Pool :连接池组件 Management Services & Utilities :管理服务和工具组件 SQL Inte ...

  4. mysql的一个字段最多能插入多少数据?我们存入text类型的值上限是多大?

    文章目录 一.前言 二.mysql的行大小限制 1.结论如下 2.行大小限制 3.页大小设置以及特性 (1)查看当前数据页大小 (2)关于数据页的解释 4.text类型和blob类型的特殊之处 5.t ...

  5. 关于InnoDB存储引擎 text blob 大字段的存储和优化--转载

    最近在数据库优化的时候,看到一些表在设计上使用了text或者blob的字段,单表的存储空间已经达到了近100G,这种情况再去改变和优化就非常难了 一.简介 为了清楚大字段对性能的影响,我们必须要知道i ...

  6. mysql中整数类型后面的数字,是不是指定这个字段的长度?比如int(11),11代表11个字节吗?...

    原先对mysql不太理解,但也没有报错.但理解的不够深入.这次补上. 原来以为int(11)是指11个字节,int(10)就是10个字节.我错了. http://zhidao.baidu.com/li ...

  7. mysql中整数类型后面的数字,是不是指定这个字段的长度?比如int(11),11代表11个字节吗?

    原先对mysql不太理解,但也没有报错.但理解的不够深入.这次补上. 原来以为int(11)是指11个字节,int(10)就是10个字节.我错了. http://zhidao.baidu.com/li ...

  8. MySql中的longtext字段的返回问题

    最近开发中用到了longtext这种字段.在mysql中该字段的最大长度为4G 如下图所示 开发中遇到的一个问题就是.例如有个article表,然后我们的页面要将数据以列表的形式展示到前端(只显示几个 ...

  9. mysql储存大文本_mysql 的大文本存储TEXT BLOB

    TEXT & BLOB 一般在保存少量字符串的时候,我们会选择 CHAR 或者 VARCHAR:而在保存较大文本时, 通常会选择使用 TEXT 或者 BLOB,二者之间的主要差别是 BLOB ...

  10. mysql高效查出重复的手机号_Mysql必读MySQL大表中重复字段的高效率查询方法

    <MysqL必读MysqL大表中重复字段的高效率查询方法>要点: 本文介绍了MysqL必读MysqL大表中重复字段的高效率查询方法,希望对您有用.如果有疑问,可以联系我们.MysqL大表重 ...

最新文章

  1. Linux12-bash变量和逻辑运行
  2. 他们创造了编程语言,他们是这个时代伟大的父亲
  3. HDU2020 绝对值排序
  4. 第四百三十六天 how can I 坚持
  5. 信息系统项目管理师-知识、变更、战略管理核心知识点思维脑图
  6. JavaScript语言精粹--执行环境及作用域,this
  7. 回答一下这些游戏帧数有关的问题吗?
  8. DataRow 点不出 Select
  9. 一名不加班的运维,怎能不会善待混合云容器
  10. CSS/HTML/JS实现图片轮播
  11. c语言编写比赛评分程序,比赛评分系统c语言课程设计.doc
  12. 教你如何关闭445端口
  13. 计算机天空之城音乐谱,天谕手游天空之城乐谱代码是什么
  14. TMS320F28335项目开发记录5_28335之CCS编程基础
  15. 我们都应该停止三种测试实践
  16. Vue路由,关于地址栏没有问题,router-view是一片空白
  17. python怎么切片_python之切片操作
  18. 产品 · B端生意的定义和分类
  19. 用python发送叮叮消息
  20. 电脑小白必备的五款软件,让你的电脑变身神器

热门文章

  1. 【win10操作系统基础】我的电脑 控制面板 win10桌面图标有个箭头如何不显示 去掉win10桌面图标箭头的方法
  2. 快速理解三角函数:积化和差、和差化积
  3. ov7725图像帧率计算公式总结
  4. PHP 伪装IP地址 数据采集 GET、POST请求
  5. 【Python 爬虫系列非专业教学】(3)手把手教你获取猫眼电影 Top 100 榜单
  6. vue的自定义指令 - Directive
  7. 懒羊羊的作业:看过国产动画片的同学都知道,懒羊羊是一只非常懒的羊,整天除了吃就是睡,根本没有时间做作业。明天就是周一了,村长慢羊羊留的作业:把 n 个整数从大到小排序,它还没开始写...
  8. 如何写好一篇技术文章?
  9. 马克飞象 Markdown 使用和学习
  10. Google pixel 原生安卓出现 WiFi 网络受限、优化网速、网络无法连接问题