DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?

netcat20000
发布于 2022-7-14 15:57
浏览
0收藏

 

本期诊断日主要分享内容:数据库库表中的细节设计-数据类型相关案例。

 

在MySQL的使用和运维工作中,大家往往会把大量精力集中在如何优化慢SQL、如何设计数据库架构以及如何使用最佳时间的配置组合来提升数据库的访问性能上,但对于库表设计往往都比较随意。

 

其实良好的数据库逻辑设计和物理设计才是高性能的基石,在对于schema的设计中要求大家既要关注全局,也需要关注细节。

 

通过本次案例分享,会让大家以一个全新的视角去回顾自己的MySQL知识体系,也会让大家发现一些网红资料的错误,避免在工作中重蹈覆辙,利用DBbrain来解决数据库运维的疑难杂症。

 

PartⅠ 从常见的知识说起

 

首先我们先来说一说关于varchar的一些简单概念。

 

一提到varchar这个数据结构,最先想起来的一定是char、text、blob这些数据结构,那么我们就简单对比下它们的使用限制和异同点。

 

1. VARCHAR(N)

 

①存储限制

• varchar 字段是将实际内容单独存储在聚簇索引之外,内容开头用1~2个字节表示实际长度(长度超过255时需要2个字节),最大内容长度不能超过65533。

②编码影响

• gbk,每个字符最多占2个字节,最大长度不能超过32766;    

• utf8,每个字符最多占3个字节,最大长度不能超过21844。

 

2. CHAR(N)和VARCHAR(N)

 

①CHAR(N)

• CHAR列的长度为固定的,N取值可以为0~255之间

• CHAR值右边填充空格以达到指定的长度。

• CHAR检索时,尾部的空格被删除掉。

• CHAR在存储或检索过程中不进行大小写转换。

• CHAR存储定长数据方便,索引效率高,例如 char(5),不论存储的数据是否达到了5个字节,都占5个字节的空间,不足的用空格填充。

 

②VARCHAR(N)

•  VARCHAR列长度为可变长字符串,N取值可以为0~65535之间,最大有效长度由最大行大小和使用的字符集确定。

• VARCHAR值保存时只保存需要的字符数,另加1个(当声明的长度超过255时,使用2个)字节来记录长度。

• VARCHAR值不进行填充,尾部的空格仍保留。

• VARCHAR存储变长数据,存储效率没有 CHAR高,但Innodb引擎,推荐使用varchar代替char。

 

3. VARCHAR、TEXT、BLOB

①VARCHAR,BLOB和TEXT类型是变长类型,对于其存储需求取决于列值的实际长度,而不是取决于类型的最大可能尺寸。

② BLOB和TEXT类型需要1,2,3或4个字节来记录列值的长度。

③ VARCHAR需要定义大小,有65535字节的最大限制,BLOB、TEXT则不需要(超过列类型最大长度的值赋给BLOB或TEXT列,值被截断)。

④BLOB可以储存图片(能保存可变数量的数据的二进制的大对象),TEXT只能储存纯文本文件。

⑤BLOB值的排序和比较是大小写敏感的方式执行, TEXT值是大小写不敏感的。

 

Part Ⅱ 关于VARCHAR(N)中N的理解陷阱

 

Varchar(N)的N到底是什么意思?或者换句话说,Varchar(N)到底能存储多少数据呢?这个问题,我相信一般情况下会有听到这两种不同的答案。

• N指的是可存储N个字节;

• N指的是可存储N个字符;

 

相信有经验的DBA对这两个答案都不会陌生,这两个答案也可以是对的,也可以认为是不全面的,那么接下来可能大家会在网上看到这样的一条解释,如下图:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

这个解释乍一看确实分析的比较全面了,把开头说到的两种答案也都涵盖了,但是我们可以关注下,最后半句话,确实存在一些容易让人产生误解和疑惑的地方,我们用一个测试来说明下:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

这个实例的版本是5.6的,测试结果跟网上科普的知识产生了出入,在varchar中声明了10个字符长度,为什么中文值存储了3个,让我们看一下产生的warning是什么:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

从waring中我们可以发现,值被depname的值越界了,被截断了,那么在严格的模式下,这条记录的插入是会报错了,肯定会影响到业务的使用。

 

接着我们利用两个函数来看一下实际的存储情况,length()和char_length(),length()函数是查看该字段占用存储的字节数,而char_length()是查看该字段占用存储的字符数。

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

看到这个结果,我们至少解答了1个疑问,varchar(N)的N确实是指的N个字符,但是如果把这个解读为长度限制是N个字节,也没有问题,因为在这个例子里length=char_length。

 

那么,这个问题其实就是关于字节和字符的对应关系的问题了,这里就不展开了,相关测试有兴趣的同学们可以自己测一下,结果如下:

• lan1字符集:1character=1bytes

• utf8字符集:1character=3bytes

• gbk字符集:  1character=2bytes

 

看到这里,我相信大家对于为什么varchar(10)只能存在3个汉字的情况有一些思路了吧,对,这肯定跟表的字符集有关,那么我们把表的字符集改成utf8测试下:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

这次的测试结果,可以看出varchar(10)确实是可以存储10个字符的数据,那么之前的问题就比较清晰了,varchar(N)存储中文的个数会受到字符集的影响。接着在网上又会发现有这样的解释:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

按照这样的说法,第一个测试的结果应该可以存储下5个汉字才对,但是实际情况下只有3个,那么问题又出在哪了呢?我们再继续看下面这个截图:

DBbrain诊断日 | 这个匪夷所思的数据库故障,你会处理吗?-鸿蒙开发者社区

同样的表,现在可以插入5个汉字了?这个测试确实证实了上面latin1中1个汉字=2个字符的观点,但是这个测试与第一个测试有哪些不用呢?问题就在与第一个测试的汉字使用的是utf8编码,而第这个测试的汉字是gbk编码,所以汉字在gbk编码转换成latin1时,占用了2个字符,而utf8编码的汉字在转换成latin1时占用了3个字符。

 

这样对于varchar(N)的N的解释,其实可以这样理解:

Mysql4.0之前,N代表的是N个字节;Mysql5.0之后,N代表的是N个字符,但是latin1表存储汉字时,要根据汉字源编码格式进行转换字符数。

1汉字(gbk),在latin1中占用2个字符;1汉字(utf8),在latin1中占用3个字符 。

 

Part Ⅲ latin1、utf8、gbk转换的原理

 

这个原理简单说明下,Latin1是ISO-8859-1的别名,ISO-8859-1编码是单字节编码,ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,本身是不支持中文的。但是他的单字节编码的方式恰恰能够通过个字符的组合来标表中文。

 

比如,“中”这个字,在gbk(双字节编码)的编码中存储的是“D6D0”,那么转换成latin1的编码,其实是用2个单字节编码实现的,即是“D6 D0”,所以在gbk中占用1个字符,转换后在latin1中占用2个字符。

 

同理,“中”字在utf8(中文三字节)的编码中存储的是“E4B8AD”,那么转换成latin1的编码,其实是用3个单字节编码实现的,即是“E4B8AD”,所以在utf8中占用1个字符,转换后在latin1中占用3个字符。

 

以上分享的案例相信大家可能在平时的工作中并不会经常碰到,但却是一个能够检验对数据库细节概念理解是否深入的试金石,希望本次分享对大家今后的数据库学习和工作能有所帮助。

 

数据库的疑难杂症一般需要多年经验才能给出准确的解法,也需要多样的场景才能覆盖比较全面的问题类型。经验与场景,一不好传承,二变化较快,三他人理解不易。而且优化手段难,找出问题了,知道怎么办了,也并不意味着就能马上解决问题,甚至有些解法是要深入到数据库引擎层代码优化,这可不是一朝一夕就能做好的。

 

为了能够帮助大家完美的解决数据库问题,在今天分享的最后给大家简单的介绍一款智能运维平台-数据库智能管家DBbrain,那DBbrain到底是什么?能够怎么帮助我们完成数据库运维工作呢?

 

DBbrain 是一个能够为云上云下用户提供数据库性能、安全、管理等功能的智能运维平台。


• 性能优化:利用机器学习、大数据手段快速复制资深数据库管理员的成熟经验,将大量数据库问题的诊断优化工作自动化,服务于云上和云下企业。

• 安全防护:提供从用户行为安全、SQL安全到数据存储加密安全等多项数据安全服务,公安部认证的等保合规性安全产品。

• 数据库管理(DMC):提供免安装、免运维、即开即用、多种数据库类型与多种环境统一的web数据库管理终端。

 

数据库智能管家DBbrain目前线上支持的功能包括:实例概览、实例管理、全实例监控、异常诊断、实时会话、健康报告、慢SQL分析、空间分析、SQL透视、SQL优化器以及数据库管理DMC。

 

面对如此丰富和全面的功能,对DBbrain不熟悉的使用者可能会有种“幸福的烦恼”,很可能并不知道从哪下手,后续的“DBbrain诊断日”会深入结合功能的使用场景给大家进行使用案例的分享,今天先挑选一些核心功能简单分享一些使用场景。

 

1. 异常诊断

 

异常诊断功能为用户的数据库实例提供实时的性能监控、故障诊断和优化,用户既可以直观地感知数据库实例实时的运行状况,也可以定位实时出现的性能异常,并根据优化建议进行系统优化。

 

2. 全实例监控

 

为用户提供全实例维度(用户整体视角)的数据库监控指标展示,特别是节假日/大促等活动时在家或者公司值班的同事(春节值班的同事可以关注下),可以高效利用这个功能实时关注公司数据库实例各项指标变动情况,省去了密密麻麻的滞后告警和监控切换。

 

3. 空间分析

 

可以查看实例空间的使用率,包括数据空间和日志空间的大小、空间使用率的日均增长量、预估的可用天数,以及查看实例下表空间所占用的空间详情。通过此功能可以提前了解资源使用的情况,预先做好资源的规划和清理,避免了在关键时刻由于资源不足或者扩容时间问题导致的业务故障。

 

4. 慢 SQL 分析

 

对实例中慢 SQL 的记录和执行信息进行统计、抽样、聚合。针对聚合后的 SQL 语句、执行计划、综合资源消耗、扫描和返回集合大小、索引使用合理性等,对慢 SQL 的性能进行分析,并给出优化建议。

 

4. 数据库管理DMC

 

提供免安装、免运维、即开即用、多种数据库类型与多种环境统一的web数据库管理终端。

 

5. 健康报告

 

能定期对数据库实例进行健康巡检,并根据用户自定义时间范围输出对应的健康报告,帮助用户深入了解数据库实例健康情况、发生的故障以及存在的隐患,同时给出专业的优化建议供用户参考。强烈推荐大家利用DBbrain的健康报告功能,在春节前为业务的数据库进行一键巡检,及时发现存在的隐患和故障,在节前按照优化建议进行改造,能够有效提升数据库在节假日期间的稳定和降低故障发生的概率。

 

Part Ⅳ Q&A

 

Q1:一个表中,有20多个blob字段 ,是打包成一个字段,还是保留20多个字段好?这两种设计读写性能有差别吗?

A1:这需要结合具体业务的场景来综合分析,简单来说建议把冷热数据分开存储,经常变更和查询的小字段和一些存日志或者内容的大字段分表存放,可以冗余一些小字段进行关联,回到之前问题中咨询说到的20多个blob是否要合到一个字段以及性能的事上,也要结合业务mysql的一些参数配置来看。比如row_format和innodb_page_size,如果采用了comoressed和dynamic的话,其实就算存在同一个大字段,也只会保留20字节的指针,只想真实存放它的溢出段地址。如果用compact的话,大于768bytes的会发生溢出。对于大字段的性能一般比较在意的就是检索性能和IO了,如果内容不是同一类型,建议分开存储,采用前缀索引查,不建议使用全文索引;IO的话也是类似,只是定期down下来就无所谓了,要是在日常查询中经常需要查找还是建议分开存,避免使用select * ,只查询需要的字段,如果是冷数据用compress()压缩后存成一个字段比较合适。

 

具体的关于大字段可以参考迪B课堂的一篇分享:深入浅出解读MySQL数据行溢出


Q2:DBbrain产品只针对在腾讯云购买的数据库吗?

A2:当前阶段只支持腾讯云数据库,后续版本中我们将支持其他数据库来帮助大家进行数据库运维,敬请期待。

 

文章转自公众号:腾讯云数据库

分类
标签
已于2022-7-14 15:57:17修改
收藏
回复
举报
回复
    相关推荐