4、Schema与数据类型优化

良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计schema,这往往需要权衡各种因素。例如,反范式的设计可以加快某些类型的查询,但同时可能使另一些类型的查询变慢。比如添加计数表和汇总表时一种很好的优化查询的方式,但这些表的维护成本很高。

选择优化的数据类型

Mysql支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要。下面几个原则有助于做出更好的选择。

  • 更小的通常更好

一般情况下,应该尽量使用可以正确存储数据的最小数据类型。更小的数据类型通常更快,因为他们占用更少的磁盘、内存和CPU缓存。并且处理时需要的CPU周期也更少。
但是要确保没有低估需要存储的值的范围,因为在schema中的多个地方增加数据类型的范围是一个非常耗时的操作。如果无法确定哪个数据类型是最好的,就选择你认为不会超过范围的最小类型。

  • 简单就好

简单数据类型的操作通常需要更少的CPU周期。例如整型字符操作代价更低,因为字符集和校对规则(字符排序规则)使字符比较比整数比较更复杂,。例如使用日志类型存储日期和时间而不是使用字符串存储;使用整型存储IP地址等等。

  • 尽量避免NULL

很多表都可能包含NULL的列,因为NULL是列的默认属性。通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。
如果查询中包含可为NULL的列,对Mysql来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更加复杂。可为NULL的列会使用更多的存储空间;可为NULL的列被索引时,每个索引记录都需要额外的字节。
通常把可为NULL的列改为NOT NULL带来的性能提升比较小,所以在进行调优时没有必要首先在现有schema中查找并修改掉这种情况。

整数类型

有两种类型的数字:整数和实数。如果存储整数,可以使用这几种整数类型:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT。分别使用8、16、24、32、64位存储空间。
整数类型有可选的UNSIGNED属性,表示不允许负值,这大致可以使正数的上限提高一倍。例如TINYINT UNSIGNED 可以存储的范围是0 ~ 255,而 TINYINT 的存储范围是 -128 ~ 127。
有符号和无符号类型使用相同的存储空间,并具有相同的性能,因此可以根据实际情况选择合适的类型。

实数类型

实数是带有小数部分的数字,然而他们不只是为了存储小数部分,也可以使用DECIMAL存储比BIGINT还大的整数。Mysql即支持精确类型,也支持不精确类型。
FLOAT和DOUBLE类型支持使用标准的浮点运算进行近似计算。
DECIMAL类型用于存储精确的小数,在Mysql5.0和更高版本DECIMAL类型支持精确计算,老版本则使用浮点运算来实现DECIMAL的计算。DECIMAL只是一种存储格式,在计算中会转换为DOUBLE类型。

字符串类型

VARCHAR 和 CHAR 类型

存储引擎存储CHAR或者VARCHAR值的方式在内存中和在磁盘上可能不一样,所以Mysql服务器从存储引擎读出的值可能需要转换另一种存储格式。

VARCHAR

用于存储可变长字符串,是最常见的字符串数据类型。他比定长类型更节省空间,因为他仅使用必要的空间。但是Mysql表使用ROW_FORMAT=FIXED创建的话,每一行都会使用定长存储,这会很浪费空间。
VARCHAR需要使用1或2个额外字节记录字符串的长度,如果列的最大长度小于或等于255字节,则只使用1个字节表示,否则使用2个字节。
VARCHAR节省了存储空间,所以对性能也有帮助。但是,由于行是变长的,在UPDATE时可能使行变得比原来更长,这就导致需要做额外的工作。如果一个行占用的空间增长,并且在页内没有更多的空间可以存储,在这种情况下,不同的存储引擎的处理方式是不一样的。InnoDB需要分裂页来使行可以放进页内。
下面这些情况下适合使用VARCHAR类型:字符串列的最大长度比平均长度大很多;列的更新少,所以碎片不是问题;使用了UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。
在Mysql5.0或者更高版本,Mysql在存储和检索时会保留末尾空格。

CHAR

CHAR是定长的,Mysql总是根据定义的字符串长度分配足够的空间。当存储CHAR值时,Mysql会删除所有的末尾空格。
CHAR适合存储很短的字符串,或者所有值都接近同一个长度。

BLOB和TEXT类型

BLOB和TEXT都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。
实际上他们分别属于不同的数据类型家族:字符类型是TINYTEXT、SMALLTEXT、TEXT、MEDIUTEXT、LONGTEXT;对应的二进制类型是BLOB、SMALLBLOB、BLOB、MEDIUBLOB、LONGBLOB。
Mysql把每个BLOB和TEXT当做一个独立的对象处理。存储引擎在存储时通常会做特殊处理。当BLOB和TEXT值太大时,InnoDB会使用专门的外部存储区域来进行存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储区域存储实际的值。

使用枚举代替字符串类型

枚举可以把一些不重复的字符串存储成一个预定义的集合。Mysql在存储枚举时非常紧凑,会根据列表值的数量压缩到一个或者两个字节中。Mysql在内部会将每个值在列表中的位置保存为整数,并且在表的.frm文件中保存“数字-字符串”映射关系的查找表。
枚举最不好的地方就是字符串列表时固定的,添加或删除字符串必须使用ALTER TABLE。

日期和时间类型

Mysql能存储的最小时间粒度为秒,但是Mysql也可以使用微秒级的粒度进行临时运算。
Mysql提供两种相似的日期类型:DATETIME和TIMESTAMP

DATETIME

这个类型能保存大范围的值,从1001到9999年,精度为秒。他把日期和时间封装到格式为YYYYMMDDHHMMSS的整数中,与时区无关。使用8个字节的存储空间。
默认情况下,Mysql以可排序的格式显示DATETIME值。

TIMESTAMP

保存了从1970年1月1日午夜以来的秒数,他和UNIX时间戳相同。TIMESTAMP只使用4个字节的存储空间,因此他的范围比DATETIME小得多,只能从1970到2038年。
TIMESTAMP显示的值依赖于时区。
通常情况下应该尽量使用TIMESTAMP,因为他比DATETIME空间效率更高。

位数据类型

Mysql有少数几种存储类型使用紧凑的位存储数据。所有这些位类型,不管底层存储格式和处理方式如何,从技术上来说都是字符串类型。

BIT

在Mysql5.0之前,BIT是TINYINT的同义词。Mysql5.0以后这是一个特性完全不同的数据类型。
可以使用BIT列在一列中存储一个或多个true/false值。BIT(1)定义一个包含单个位的字段,BIT(2)存储2个位,依此类推。BIT列的最大长度是64位。
Mysql把BIT当做字符串类型,而不是数字类型。

SET

如果需要保存很多true/false值,可以考虑合并这些列到一个SET数据类型,他在Mysql内部是以一系列打包的位的集合来表示的。这样就有效的利用了存储空间。并且Mysql有像FIND_IN_set()和FIELD()这样的函数。他的主要缺点是改变列的定义代价较高,需要ALTER TABLE操作。

在整数列上进行按位操作

一种替代SET的方式是使用一个整数包装一系列的位。

选择标识符

为标识列选择合适的数据类型非常重要。一般来说更有可能用标识列与其他值进行比较,或者通过标识列寻找其他列。标识列也可能在另外的表中作为外键使用,所以为标识列选择数据类型时,应该选择跟关联表中的对应列一样的类型。
当选择标识列的类型时,不仅仅需要考虑存储类型,还需要考虑Mysql对这种类型怎么执行计算和比较的。

整数类型

整数通常是标识列最好的选择,因为他们很快并且可以使用AUTO_INCREMENT。

ENUM和SET类型

对于标识列来说,ENUM和SET类型通常是一个糟糕的选择,尽管对某些只包含固定状态或者类型的静态定义表来说可能是没有问题的。ENUM和SET适合存储固定信息,如状态,类型等。

字符串类型

如果可能应该避免使用字符串类型作为标识列,因为很耗空间,并且通常比数字类型慢。
对于完全随机的字符串例如MD5,UUID产生的字符串,这些函数生成的值会任意分布在很大的空间内,这会导致INSERT以及一些SELECT语句变得很慢:

  • 因为插入值会随机写到索引的不同位置,所以使得 INSERT 语句更慢,这会导致页分裂、磁盘随机访问,以及对于聚簇存储引擎产生聚簇索引碎片。
  • SELECT语句会变得更慢,因为逻辑上相邻的行会分布在磁盘和内存的不同的地方。
  • 随机值导致缓存对所有类型的查询语句效果都很差,因为会使得缓存赖以工作的访问局部性原理失效。

特殊类型数据

某些类型的数据并不直接与内置类型一致。例如低于秒级精度的时间戳。
另一个例子就是IPv4地址。我们经常用字符串来存储IP地址。然后实际上是32位无符号整数。

Mysql schema设计中的陷进

太多的列

Mysql的存储引擎API工作时需要再服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲中将编码过的列转换成行数据结构的代价非常高。转换的代价依赖于列的数量。

太多的关联

所谓的“实体-属性-值”设计模式是一个常见的糟糕的设计模式,尤其是在Mysql中。Mysql限制了每个关联操作最多只能有61张表。如果希望查询执行的快速且并发性好,单个查询最好在12个表内。当然在实际开发过程过很少会有这么多表的关联。

全能的枚举

防止过度使用枚举。

变相的枚举

枚举列允许在列中存储一组定义值中的单个值,集合SET列则允许在列中存储一组定义值中的一个或多个值。

范式和反范式

对于任何给定的数据通常都有很多种表示方法,从完全的范式化到完全的反范式化,以及两者的折中。在范式化的数据库中,每个事实数据会出现并且只出现一次。相反,在反范式化的数据库中,信息是冗余的,可能会存储在多个地方。

范式的优点和缺点

优点

范式化的更新操作通常比反范式化要快。
当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据。
范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快。
很少有多余的数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句。

缺点

通常需要更多的关联。稍微复杂一点的查询在符合范式的schema上都需要至少一次关联。

反范式的优点和缺点

反范式化的schema因为所有数据都在一张表中,可以很好地避免关联。

混用范式化和反范式化

缓存表和汇总表

有时提升性能最好的方法是在同一张表中保存衍生的冗余数据。然而有时也需要创建一张完全独立的汇总表或缓存表。

物化视图

物化视图实际上是预先计算并且存储在磁盘上的表,可以通过各种各样的策略刷新和更新。Mysql并不原生支持物化视图。

计数器表

加快ALTER TABLE操作的速度

Mysql的ALTER TABLE操作的性能对大表来说是个大问题。Mysql执行大部分修改表结构操作的方法是用新的结构创建一个空表,从旧表中查出所有数据插入新表,然后删除旧表。这样的操作可能需要花费很长的时间,如果内存不足而表又很大,而且还有很多索引的情况下尤其如此。

只修改.frm文件

修改表的.frm文件时很快的,但是Mysql有时候会在没有必要的情况下重建表。
下面的一些操作可能不需要重建表:

  - 移除一个列的AUTO_INCREMENT属性。- 增加、移除或者修改ENUM和SET常量。

快速创建MyISAM索引

为了高效地载入数据到MyISAM表中,有一个常用的技巧是先禁用索引,载入数据,然后重新启动索引。因为构建索引的工作呗延迟到数据完全加载之后了,这个时候可以通过排序来构建索引。这样做会使索引树的碎片更少,更紧凑。
但是这个方法对唯一索引无效,因为DISABLE KEYS 只对非唯一索引有效。MyISAM会在内存中构造一个唯一索引并且为载入的每一行数据检查唯一性,一旦索引的大小超过了有效内存大小,载入操作就会越来越慢。
在InnoDB中有一个类似的技巧,依赖于InnoDB的快速在线索引创建功能。先删除所有的非唯一索引,然后增加新的列,最后重新创建删除掉的索引。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/194428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

error转string

1 概述 在golang中,error类型是非常常见的一种数据类型。在开发过程中,经常会遇到需要将error类型转换成string类型的情况。本文主要介绍几种常见的golang error转string的方法。 2 使用Error()函数 在golang中,Error()函数是error类型的一…

Redis--15--缓存穿透 击穿 雪崩

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 缓存穿透 击穿 雪崩运行速度:1 缓存穿透问题描述:如何解决: 2 缓存击穿问题描述:如何解决: 3 缓存雪崩说明:解决方案: 缓存穿透 击穿 雪崩 问题描述: 由于海量的用…

springboot单元测试关闭日志

在logback中关闭日志 在test目录下新建文件夹resources&#xff0c;新增文件logback-test.xml文件 在logback-test.xml 文件中&#xff0c;添加内容&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <configuration><include resourc…

Java的多态性

Java是一种面向对象的编程语言&#xff0c;多态性是其核心特性之一。通过多态性&#xff0c;我们可以编写出灵活、可扩展的代码&#xff0c;提高代码的可维护性和可复用性。本文将详细介绍Java中的多态性概念、实现方式和示例代码&#xff0c;帮助读者深入理解和应用多态性。 …

一缕青丝寄相思

10年8月16日七夕节男孩向女孩表白,女孩不知道那天是七夕,也没有读懂男孩的爱,女孩在9月22日中秋,向男孩打开了心门,男孩却没有懂女孩的心思.13年后的一封问候邮件,一束女孩的长发和回不去的青春 洒满阳光的午后 转眼间看到你的笑脸 微笑着你对我说 遇上你认识我真好 你说得好莫…

33、LED呼吸灯直流电机调速

LED呼吸灯 main.c #include <REGX52.H>sbit LEDP2^0;void Delay(unsigned int t) {while(t--); }void main() {unsigned char Time,i;while(1){for(Time0;Time<100;Time) //改变亮灭时间&#xff0c;由暗到亮{for(i0;i<20;i) //计次延时{LED0; //LED亮Del…

免费HTTPS证书

什么是HTTPS呢&#xff1f;HTTPS全称为Hyper Text Transfer Protocol Secure&#xff0c;即超文本传输安全协议。它是在HTTP的基础上加入了SSL/TLS协议&#xff0c;可以对传输的数据进行加密&#xff0c;有效防止数据被第三方截取或篡改&#xff0c;从而保障了用户的信息安全。…

实时设计#N3期训练营DONE,ComfyUI中文社区@上海

作为主办方&#xff0c;我们非常高兴能够举办这次AIGC训练营&#xff0c;重点解决Comfyui的安装和入门。活动在下午1:30开始&#xff0c;在上海永兴仓库举行。 首先&#xff0c;我们向参与者介绍了本次活动的目的和安排&#xff0c;让大家对活动有一个清晰的认识。 接着&#x…

J-Link RTT的使用(原理 + 教程 + 应用 + 代码)

MCU:STM32F407VE MDK:5.29 IAR:8.32 目录--点击可快速直达 目录 写在前面什么是RTT?RTT的工作原理RTT的性能快速使用教程高级使用教程附上测试代码2019年12月27日更新--增加打印float的功能 写在前面 本文介绍了J-Link RTT的部分使用内容&#xff0c;很多地方参考和使用…

28、DS18B20温度传感器

DS18B20介绍 DS18B20是一种常见的数字温度传感器&#xff0c;其控制命令和数据都是以数字信号的方式输入输出&#xff0c;相比较于模拟温度传感器&#xff0c;具有功能强大、硬件简单、易扩展、抗干扰性强等特点 测温范围&#xff1a;-55C 到 125C 通信接口&#xff1a;1-Wire…

考研英语语法(三十八)

特殊结构的长难句分析-嵌套结构 分辨是否嵌套 先断开句子 如果一个从句没结束&#xff0c;另一个从句又开始了&#xff0c;就发生了嵌套 再一层层的看嵌套&#xff0c;进行整合 例句 The great question is who should benefit from t…

DeDeCMS v5.7 SP2 正式版 前台任意用户密码修改(漏洞复现)

1.环境搭建 PHP 5.6 DeDeCMSV5.7SP2 正式版 安装phpstudy&#xff0c;https://www.xp.cn/小皮面板 先启动Apache2.4.39和MySQL5.7.26 如果他会让你下载&#xff0c;点击是就好&#xff01; 让后点击网站—>点击创建网站 域名自己创建&#xff0c;自己取 其他的不变 点击…

6-69.鸭子也是鸟

按要求完成下面的程序&#xff1a; 1、定义一个Bird类&#xff0c;包含一个void类型的无参的speak方法&#xff0c;输出“Jiu-Jiu-Jiu”。 2、定义一个Duck类&#xff0c;公有继承自Bird类&#xff0c;其成员包括&#xff1a; &#xff08;1&#xff09;私有string类型的成员na…

SCAU:大于平均分

大于平均分 Time Limit:1000MS Memory Limit:65535K 题型: 编程题 语言: G;GCC 描述 输入10个整数&#xff0c;计算它们的平均值&#xff0c;并统计有多少个数比平均值大。输入格式 10个整数输出格式 比平均值在的数的个数输入样例 0 1 2 3 4 5 6 7 8 9输出样例 5 …

Flutter: Websocket的使用与封装

1.引入相关插件库 # websocketweb_socket_channel: ^2.4.0# 引入rxdart 解决Bad state: Stream has already been listened to.的报错问题rxdart: ^0.27.7# 状态管理*provider: ^6.0.5 2.代码编写及封装 import dart:async;import package:rxdart/subjects.dart; import pack…

西北大学计算机844考研-最后20天复习重点

西北大学计算机844考研-最后20天复习重点 ​ 我做844辅导超过400小时&#xff0c;人数超过20余人&#xff0c; 现在是2023年12月03日晚上22:33&#xff0c;这篇文章旨在帮助844众多考研学子在最后20天稳住心态&#xff0c;科学备考&#xff0c;争取获得专业课高分&#xff0c;…

使用求2个字符串最短编辑距离动态规划算法实现 git diff 算法 java 实现

测试类 MyDiffTest.java&#xff1a; import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import java.util.List;public class MyDiffTest {private static String path "\\xxx\\";private static List<String> lines…

Springboot启动原理解析

我们开发任何一个Spring Boot项目&#xff0c;都会用到如下的启动类 SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);} } 从上面代码可以看出&#xff0c;Annotation定义&#x…

Янгель杨格尔年谱

米哈伊尔 库兹米其 杨格尔 生于1911年11月7日&#xff08;旧历10月25日&#xff09;&#xff0c;沙俄伊尔库斯克省。逝世于1971年10月25日。 出生于农民家庭&#xff0c;有11个兄弟姐妹。 1926年6年级结束后前往莫斯科投奔哥哥。 1929年在学校学徒毕业&#xff08;&#xf…

网络运维与网络安全 学习笔记2023.12.3

网络运维与网络安全 学习笔记 第三十三天 今日目标 目录-文件基本管理、vim文本编辑、用户账号管理 组账号管理、归属控制、权限控制 目录-文件基本管理 ls 列目录及文档属性 ls - List 格式:ls[选项]…[目录或文件路径] 1.如果不以/开始,表示相对路径(省略了当前所在位置…