MySQL 高性能表设计规范

栏目: 数据库 · Mysql · IT技术 · 发布时间: 6年前

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

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

一、选择优化的数据类型

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

更小的通常更好

更小的数据类型通常更快, 因为它们占用更少的磁盘、 内存和CPU缓存, 并且处理时需要的CPU周期也更少。

简单就好

简单数据类型的操作通常需要更少的CPU周期。 例如, 整型比字符操作代价更低, 因为字符集和校对规则(排序规则 )使字符比较比整型比较更复杂。

尽量避免NULL

如果查询中包含可为NULL 的列, 对 MySQL 来说更难优化, 因为可为NULL 的列使得索引、 索引统计和值比较都更复杂。 可为NULL的列会使用更多的存储空间, 在MySQL里也需要特殊处理。 当可为NULL的列被索引时, 每个索引记录需要一个额外的字节, 在MyISAM里甚至还可能导致固定大小的索引(例如只有一个整数列的索引)变成可变大小的索引。
当然也有例外, 例如InnoDB 使用单独的位 (bit) 存储NULL值, 所以对于稀疏数据有很好的空间效率。

1.整数类型

有两种类型的数字:整数 (whole number) 和实数 (real number) 。 如果存储整数, 可以使用这几种整数类型:TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT。分别使用8,16, 24, 32, 64位存储空间。

整数类型有可选的 **UNSIGNED ** 属性,表示不允许负值,这大致可以使正数的上限提高一倍。 例如 TINYINT. UNSIGNED 可以存储的范围是 0 – 255, 而 TINYINT 的存储范围是 -128 -127 。

有符号和无符号类型使用相同的存储空间,并具有相同的性能 , 因此可以根据实际情况选择合适的类型。

你的选择决定 MySQL 是怎么在内存和磁盘中保存数据的。 然而, 整数计算一般使用64 位的 BIGINT 整数, 即使在 32 位环境也是如此。( 一些聚合函数是例外, 它们使用DECIMAL 或 DOUBLE 进行计算)。

MySQL 可以为整数类型指定宽度, 例如 INT(11), 对大多数应用这是没有意义的:它不会限制值的合法范围,只是规定了MySQL 的一些交互工具(例如 MySQL 命令行客户端)用来显示字符的个数。 对于存储和计算来说, INT(1) 和 INT(20) 是相同的。

2.实数类型

实数是带有小数部分的数字。 然而, 它们不只是为了存储小数部分,也可以使用DECIMAL 存储比 BIGINT 还大的整数。

FLOAT和DOUBLE类型支持使用标准的浮点运算进行近似计算。
DECIMAL类型用于存储精确的小数。
浮点和DECIMAL类型都可以指定精度。 对于DECIMAL列, 可以指定小数点前后所允许的最大位数。这会影响列的空间消耗。

有多种方法可以指定浮点列所需要的精度, 这会使得MySQL选择不同的数据类型,或者在存储时对值进行取舍。 这些精度定义是非标准的,所以我们建议只指定数据类型,不指定精度。

浮点类型在存储同样范围的值时, 通常比DECIMAL使用更少的空间。FLOAT使用4个字节存储。DOUBLE占用8个字节,相比FLOAT有更高的精度和更大的范围。和整数类型一样, 能选择的只是存储类型; MySQL使用DOUBLE作为内部浮点计算的类型。

因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用DECIMAL。但在数据最比较大的时候, 可以考虑使用BIGINT代替DECIMAL, 将需要存储的货币单位根据小数的位数乘以相应的倍数即可。

3.字符串类型

VARCHAR

用于存储可变⻓字符串,长度支持到65535
需要使用1或2个额外字节记录字符串的长度
适合:字符串的最大⻓度比平均⻓度⼤很多;更新很少

CHAR

定⻓,⻓度范围是1~255
适合:存储很短的字符串,或者所有值接近同一个长度;经常变更

慷慨是不明智的

使用VARCHAR(5)和VARCHAR(200)存储’hello’的空间开销是一样的。 那么使用更短的列有什么优势吗?

事实证明有很大的优势。 更长的列会消耗更多的内存, 因为MySQL通常会分配固定大小的内存块来保存内部值。 尤其是使用内存临时表进行 排序 或操作时会特别糟糕。 在利用磁盘临时表进行排序时也同样糟糕。

所以最好的策略是只分配真正需要的空间。

4.BLOB和TEXT类型

BLOB和 TEXT都是为存储很大的数据而设计的字符串数据类型, 分别采用 二进制和字符方式存储 。

与其他类型不同, MySQL把每个BLOB和TEXT值当作一个独立的对象处理。 存储引擎在存储时通常会做特殊处理。 当BLOB和TEXT值太大时,InnoDB会使用专门的 “外部“存储区域来进行存储, 此时每个值在行内需要1 – 4个字节存储 存储区域存储实际的值。

BLOB 和 TEXT 之间仅有的不同是 BLOB 类型存储的是二进制数据, 没有排序规则或字符集, 而 TEXT类型有字符集和排序规则

5.日期和时间类型

大部分时间类型都没有替代品, 因此没有什么是最佳选择的问题。 唯一的问题是保存日期和时间的时候需要做什么。 MySQL提供两种相似的日期类型: DATE TIME和 TIMESTAMP。

但是目前我们更建议存储时间戳的方式,因此该处不再对 DATE TIME和 TIMESTAMP做过多说明。

5.其他类型

5.1选择标识符

在可以满足值的范围的需求, 井且预留未来增长空间的前提下, 应该选择最小的数据类型。

整数类型

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

ENUM和SET类型

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

字符串类型

如果可能, 应该避免使用字符串类型作为标识列, 因为它们很消耗空间, 并且通常比数字类型慢。

对于完全 “随机” 的字符串也需要多加注意, 例如 MDS() 、 SHAl() 或者 UUID() 产生的字符串。 这些函数生成的新值会任意分布在很大的空间内, 这会导致 INSERT 以及一些SELECT语句变得很慢。如果存储 UUID 值, 则应该移除 “-“符号。

5.2特殊类型数据

某些类型的数据井不直接与内置类型一致。 低千秒级精度的时间戳就是一个例子,另一个例子是以个1Pv4地址,人们经常使用VARCHAR(15)列来存储IP地址,然而, 它们实际上是32位无符号整数, 不是字符串。用小数点将地址分成四段的表示方法只是为了让人们阅读容易。所以应该用无符号整数存储IP地址。MySQL提供INET_ATON()和INET_NTOA()函数在这两种表示方法之间转换。

二、表结构设计

1.范式和反范式

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

范式的优点和缺点

为性能提升考虑时,经常会被建议对 schema 进行范式化设计,尤其是写密集的场景。

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

反范式的优点和缺点

不需要关联表,则对大部分查询最差的情况——即使表没有使用索引——是全表扫描。 当数据比内存大时这可能比关联要快得多,因为这样避免了随机I/0。

单独的表也能使用更有效的索引策略。

混用范式化和反范式化

在实际应用中经常需要混用,可能使用部分范式化的 schema 、 缓存表,以及其他技巧。
表适当增加冗余字段,如性能优先,但会增加复杂度。可避免表关联查询。

简单熟悉数据库范式

2.表字段少⽽精

  • I/O高效
  • 字段分开维护简单
  • 单表1G体积 500W⾏行评估
  • 单⾏行不超过200Byte
  • 单表不超过50个INT字段
  • 单表不超过20个CHAR(10)字段
  • 建议单表字段数控制在20个以内
  • 拆分TEXT/BLOB,TEXT类型处理性能远低于VARCHAR,强制生成硬盘临时表浪费更多空间。

参考资料:

高性能mysql第三版



以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

实现领域驱动设计

实现领域驱动设计

Vaughn Vernon / 滕云 / 电子工业出版社 / 2014-3 / 99.00元

领域驱动设计(DDD)是教我们如何做好软件的,同时也是教我们如何更好地使用面向对象技术的。它为我们提供了设计软件的全新视角,同时也给开发者留下了一大难题:如何将领域驱动设计付诸实践?Vaughn Vernon 的这本《实现领域驱动设计》为我们给出了全面的解答。 《实现领域驱动设计》分别从战略和战术层面详尽地讨论了如何实现DDD,其中包含了大量的最佳实践、设计准则和对一些问题的折中性讨论。《实......一起来看看 《实现领域驱动设计》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换