良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计schema,这往往需要权衡各种因素。

例如,反范式的设计可以加快某些类型的查询,但同时可能使另一些类型的查询变慢;添加计数表和汇总表是一种很好的优化查询的方式,但这些表的维护成本可能会很高。

选择优化的数据类型

MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要。基本原则为:

  • 更小的通常更好:一般情况下尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常更快,因为其占用更少的磁盘、内存和CPU。
  • 简单就好:简单数据类型的操作通常需要更小的CPU,如整型比字符的操作代价更低,因为字符集和校对规则(排序)使字符比较比整型比较更复杂。实际例子为:应该使用MySQL内建的类型而不是字符串来存储日期和时间;应该使用整型存储IP地址。
  • 尽量避免NULL:通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值,如果计划在列上建立索引,尽量避免设计成可为NULL的列。

在为列选择数据类型时,第一步需要确定合适的大类型:数字、字符串、时间等。下一步是选择具体类型。很多MySQL的数据类型可以存储相同类型的数据,只是存储的长度和范围不一样、允许的精度不同,或者需要的物理空间(磁盘和内存空间)不同。相同大类型的不同子类型数据有时也有一些特殊的行为和属性。

如DATETIME和TIMESTAMP都可以存储日期时间数据,但是TIMESTAMP使用DATETIME一半的存储空间,并且具有随时区变化而自动更新的特性,但其可表示的时间范围又要小得多。

整数类型

整数类型共有TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分别使用8,16,24,32,64位存储空间,存储范围从-2(n-1)幂到2(n-1)幂 - 1。整数类型有可选的UNSIGNED属性,表示不允许负值,这可以使正数的上限提升一倍。MySQL可为整数类型指定宽度,如int(11),但其不会限制值的合法范围,只是规定了一些交互工具(如MySQL Client)用来显示字符的个数。对于存储和计算来说,int(1)、int(11)并无区别。

实数类型

实数是带有小数部分的数字,但也可以使用DECIMAL存储比BIGINT还大的整数,MySQL支持精确类型Decimal,也支持不精确类型Float、Double。存储相同范围的值,浮点类型通常比Decimal使用更少的空间,计算开销也更小。

字符串类型

VARCHAR类型用于存储可变长字符串,相较之定长类型更节约空间,最多能存储65535字节数据。VARCHAR需要使用1或2个额外字节记录字符串的长度:如果列的最大长度小于或等于255字节,则只使用1个字节表示,否则使用2个字节。但由于其长度是可变的,在Update时可能会使得行变得比原来更长,如果一个行占用的空间增长,并且在页内没有更多的空间存储时,InnoDB使用分裂页来使行可以放进页内。

CHAR类型是定长的,存储CHAR值时,MYSQL会删除所有的末尾空格。其适用于存储很短的字符串,如使用CHAR(1)存储Y/N,若使用VARCHAR(1)来存储,在相同字符集下会多使用一个字节来记录长度;或是接近于同一个长度,如MD5值。对于经常变更的值,char也比varchar更好,其不易产生碎片。

BLOB和TEXT类型

BLOB和TEXT都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储,分属于两组数据类型家族:TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT,LONGTEXT;对应的二进制类型是TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB。

BLOB类型没有排序规则或字符集,而TEXT类型有字符集和排序规则。BLOB和TEXT在排序时与其他类型也不一样:其只对每个列的最前max_sort_length字节而不是整个字符字符串进行排序。可配置此属性或者使用order by substring(column,length)进行部分排序。

使用枚举代替字符串类型

枚举列可以把一些不重复的字符串存储成一个预定义的集合,MYSQL存储枚举时非常紧凑,会根据列表值的数量压缩到一个或者两个字节中。MySQL内部会将每个值在列表中的位置保存为整数,并且在表的.frm文件中保存数字-字符串映射关系的查找表。下面有一个例子:

使用枚举的好处则是可以节约存储空间,不好的是,字符串列表是固定的,添加或者删除字符串必须使用ALTER TABLE,对于一系列未来可能改变的字符串,使用枚举不是个好主意。

日期和时间类型

MySQL提供两种相似的日期类型:DATETIME和TIMESTAMP,精度均为秒,对于大多数应用程序,其都能工作,但某些场景下,一个比另一个工作得更好。

DATETIME:时间范围为1001~9999年,精度为秒,其将日期时间封装到YYYYMMDDHHMMSS的整数中,与时区无关,使用8个字节存储空间。

TIMESTAMP:保存了自1970-01-01 00:00:00以来的秒数,使用4个字节的存储空间,只能表示1970~2038。TIMESTAMP显示的值依赖于时区,MySQL服务器、操作系统,以及客户端连接都有时区设置。默认情况下,如果插入时没有指定第一个TIMESTAMP列的值,MYSQL 则会设置这个列的值为当前时间;在更新一行记录时,也会默认更新第一个TIMESTAMP列的值。也可以配置TIMESTAMP的插入和更新行为,其默认为NOT NULL,其他数据类型则默认为NULL

选择标识符

为标识符选择合适的数据类型非常重要,在建立索引、联合查询时都有很大影响。选定一种类型之后,需要确保在所有关联的表中都使用同样的类型,类型之间需要精确匹配,包括UNSIGNED这样的属性。混用不同数据类型可能导致性能问题或者由隐式类型转换带来额外的问题。

  • 整数类型通常是标识列最好的选择,速度很快并且可以AUTO_INCREMENT
  • ENUM和SET通常是比较糟糕的选择,除非是固定状态信息
  • 字符串类型,也应该选择其作为标识符,但占用更多的空间(索引),通常速度慢于整型,并且其无序插入会增加索引、空间成本。

特殊数据类型

人们经常使用VARCHAR(15)来存储IPV4地址,然而它们实际上是32位无符号整数,所以应该使用无符号整数来存储IPV4地址,MySQL提供INET_ATON()和INET_NTOA()函数在字符串与无符号整数之间切换。

范式和反范式

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

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

    范式化设计的schema的缺点是通常需要关联。稍微复杂一些的查询语句在符合范式的schema上都可能需要至少一次关联,也许更多。这不但代价昂贵,也可能使一些索引策略无效。

反范式的优缺点

反范式化的schema所有数据都在一张表中,其优点为:

  • 不需要进行表关联。
  • 单独的表也能使用更有效的索引策略。

    缺点为更新操作代价过高。实际使用中一般都是范式化与反范式化共用。

缓存表和汇总表

有时提升性能最好的方法是在同一张表中保存衍生的冗余数据。然而,有时也需要创建一张完全独立的汇总表或缓存表(特别是为满足检索的需求时)。

我们用术语“缓存表”来表示存储那些可以比较简单地从schema其他表获取(但是每次获取的速度比较慢)数据的表(例如,逻辑上冗余的数据)。而术语“汇总表”时,则保存的是使用GROUP BY 语句聚合数据的表(例如,数据不是逻辑上冗余的)。

以网站为例,假设需要计算之前24小时内发送的消息数。在一个很繁忙的网站不可能维护一个实时精确的计数器。作为替代方案,可以每小时生成一张汇总表。这样一条简单的查询就可以做到,并且比实时维护计数器要高效得多。缺点是计数器并不是100%精确。

MySQL Schema 与数据类型优化的更多相关文章

  1. MySQL Schema与数据类型优化

    Schema与数据类型优化 选择优化的数据类型 1.更小的通常更好 更小的数据类型通常更快,因为它们占用更少的磁盘,内存和CPU缓存 2.简单就好 简单数据类型的操作通常需要更少的CPU周期.例如:整 ...

  2. mysql笔记01 MySQL架构与历史、Schema与数据类型优化

    MySQL架构与历史 1. MySQL架构推荐参考:http://www.cnblogs.com/baochuan/archive/2012/03/15/2397536.html 2. MySQL会解 ...

  3. Schema 与数据类型优化

    这是<高性能 MySQL(第三版)>第四章<Schema 与数据类型优化>的读书笔记. 1. 选择优化的数据类型 数据类型的选择原则: 越小越好:选择满足需求的最小类型.注意, ...

  4. 高性能MySQL笔记 第4章 Schema与数据类型优化

    4.1 选择优化的数据类型   通用原则   更小的通常更好   前提是要确保没有低估需要存储的值范围:因为它占用更少的磁盘.内存.CPU缓存,并且处理时需要的CPU周期也更少.   简单就好   简 ...

  5. MySQL Schema与数据类型的优化

    选择优化的数据类型: 1. 更小的通常更好: 一般情况下,应该尽量使用可以正确存储数据的最小数据类型.更小的数据类型通常更快,因为他们占用更少的磁盘,内存和cpu缓存,并且处理时需要的cpu周期也更少 ...

  6. MySQL之Schema与数据类型优化

    选择优化的数据类型 MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要.不管存储哪种类型的数据,下面几个简单的原则都有助于做出更好的选择: 更小的通常更好一般情况下,应该尽量使用 ...

  7. MySQL设计之Schema与数据类型优化

    一.数据类型优化 1.更小通常更好 应该尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常更快,因为它们占用更少的磁盘.内存和CPU缓存,并且处理时需要的CPU周期更少,但是要确保没有低估需要 ...

  8. Schema与数据类型优化

    良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询数据来设计schema,这往往需要权衡各种因素. MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要. 更小的通 ...

  9. Mysql高性能笔记(一):Schema与数据类型优化

    1.数据类型 1.1.几个参考优化原则 a.  更小的通常更好 i.更小的数据类型,占用更少磁盘.内存和CPU缓存,需要的CPU周期更少 ii.如果无法确定哪个数据类型是最好的,就选择不会超过范围的最 ...

随机推荐

  1. LevelDB学习笔记 (2): 整体概览与读写实现细节

    1. leveldb整体介绍 首先leveldb的数据是存储在磁盘上的.采用LSM-Tree实现,LSM-Tree把对于磁盘的随机写操作转换成了顺序写操作.这是得益于此leveldb的写操作非常快,为 ...

  2. <5人公司极简研发方案

    人过35,被年轻人卷走了一大半,还停留在这个行业的,不是在创业,就是在创业的路上. 创业很难,刚开始没钱没人,啥都要自己干,一个字累.好处是地基是自己搭的,心里有底.不过博主最近健忘的毛病愈发严重了, ...

  3. 12、关于系统cpu的计算

    1.cpu核数和逻辑cpu: CPU总核数 = 物理CPU个数 * 每颗物理CPU的核数: 总逻辑CPU数 = 物理CPU个数 * 每颗物理CPU的核数 * 超线程数 2.查看linux的cpu相关信 ...

  4. python3 依赖倒置原则示例

    场景 针对园区停车信息,需要对各个公司提供的停车数据进行整合并录入自家公司的大数据平台 数据的录入无外乎就是对数据的增删改查 下面上一个常规的写法(未符合依赖倒置),整合来自 长安和丰田 的停车数据 ...

  5. CRM系统如何帮助企业管理多条业务线的?

    在如今的市场环境中,许多企业为了提高销售效率,增加业绩收入,都会选择使用CRM客户关系管理系统来帮助进行对客户和销售的管理.CRM系统能够帮助企业在不同的产品线上同时开展营销活动.各个销售团队能够独立 ...

  6. 无需手动输入命令,简单3步即可在K8S集群中启用GPU!

    随着全球各大企业开始广泛采用Kubernetes,我们看到Kubernetes正在向新的阶段发展.一方面,Kubernetes被边缘的工作负载所采用并提供超越数据中心的价值.另一方面,Kubernet ...

  7. Linux:Ka li 2020.4 安装教程

    下载地址 Ka li官网 :https://www.kali.org install 版本是安装版,安装后使用: Live    版本可以直接启动运行: netinstaller  版本是网络安装版, ...

  8. CG-CTF WxyVM

    一. 之前一直以为虚拟机是那种vmp的强壳,下午看了一些文章才逐渐明白虚拟机这个概念,目前ctf中题目出现的都是在程序中相等于内嵌了一个虚拟机,将程序代码转换成自己定义的指令,通过内嵌的虚拟机进行解释 ...

  9. Spring Cloud中的注解

    一.Eureka @EnableEurekaServer: @EnableDiscoverClient:标注服务是一个Eureka的客户端 @LoadBalanced:自动构造LoadBalancer ...

  10. 去抖动 debounce

    最近才发现 debounce 在 减少DOM操作及资源加载方面得重要性,遂写个博客记录一下 /** * @param {Function} func 要执行的函数 * @param {number} ...