MySql教程

MySQL Schema 与数据类型优化

本文主要是介绍MySQL Schema 与数据类型优化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计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 与数据类型优化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!