Schema与数据类型优化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Schema与数据类型优化相关的知识,希望对你有一定的参考价值。
良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计schema,这往往需要权衡各种因素。本章主要为接下来的索引优化与查询优化做铺垫,覆盖了mysql特有的schem设计方面的主题。
1:选择优化的数据类型
-->更小的通常更好:一般情况下应该尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常更快,因为他们占用更小的磁盘,内核CPU缓存,并且处理时需要的CPU周期也更少。
-->简单就好:简单数据类型操作通常需要更少的cpu周期,例如,整形比字符串操作的代价更低,因为字符集和校对规则使得字符集比较比整型更加复杂。
-->尽量避免NULL:如果计划列上建立索引,就应该避免设计成可为NULL的列。
在为列悬着数据类型时,第一步需要确定合适的大类型:数字,字符串,时间等,下一步选择具体类型。
2.1:整数类型
-->存储整数的类型:TINYINT,SMALLINT,MEDIUMINT,INT,GIGINT。分别使用的存储空间为8,16,24,32,64位存储空间。它们而已存储的范围为:?2(N?1)到2(N?1)-1,N是存储空间的位数。
-->整数类型有可选的UNSIGNED属性,表示不允许负值,这大致可以使整数的上限提升一倍。
-->MySQL可以为整数类型指定宽度,例如INT(11),对于大多数应用这是没有意义的。它不会限制值得合法范围。只是规定了MySQL的交互工具(客户端)用来显示字符的个数。对于存储和计算来讲INT(1)和INT(20)是一样的。
2.2:实数类型
实数是带有小数部分的数字。MySQL支持精确类型,也支持不精确类型。
-->float和double类型支持使用标准的浮点运算进行近似计算。
-->DECIMAL类型用于存储精确的小数。在MySQL5.0+版本中DECIMAL类型支持精确计算,除非有必要,否则更应该选择考虑BIGINT乘以相应倍数代替DECIMAL,避免精确计算代价高的问题。
-->浮点和DECIMAL类型都可以指定精确度。对于DECIMAL列,可以指定小数点前后所允许的最大位数。这会影响列的空间消耗。
2.3字符串类型
VARCHAR和CHAR类型
VARCHAR
--->用于可变长字符串,比定长支付类型更节省空间,因为它仅仅使用必要空间。
-->需要1或者2个额外字节记录字符串长度。如果列的最大长度小于或者等于255,则值需要1个字节表示,否则使用2个字节。
-->MySQL4.1-版本中MySQL会删除末尾空格,5.0+版本中MySQL在存储和检索时会保留末尾空格。
-->InnoDB把过长的VARCHAR存储为BLOB。
CHAR
-->定长类型,MYSQL总是根据定义的字符串长度分配足够的空间,当存储为CHAR时,MYSQL会删除所有的末尾空格。
-->适合存储很短的字符串,或者所有值都接近同一个长度(适合存储密码的MD5值,因为这是一个定长)。适合经常变更的数据,因为定长不容易产生碎片。
-->适合非常短的列。如果采用单字节字符集只需要一个字节,但是VARCHAR(1)需要两个字节。
填充和截取空格的行为
CREATE TABLE `char_test` ( `char_col` char(10) NOT NULL DEFAULT ‘‘, `varchar_col` varchar(10) NOT NULL DEFAULT ‘‘ ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into char_test (char_col, varchar_col) values (‘string1‘, ‘string1‘),(‘ string2‘, ‘ string2‘),(‘string3 ‘, ‘string3 ‘) select concat("‘",char_col,"‘"), concat("‘",varchar_col,"‘") from char_test select * from char_test where char_col = "string3 " and varchar_col = "string3"
3BLOB和TEXT类型
-->都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。
-->字符类型:TINYTEXT,SMALLTEXT,TEXT,MEDIUMTEXT,LONGTEXT。
-->二进制类型:TINYBLOB,SMALLBLOB,BLOB,MEDIUMBLOB,LONGBLOB。
-->与其他的类型不同,MySQL把每个BLOB和TEXT值当作一个独立的对象处理。存储引擎在存储时,通常会做特殊处理。当BLOB和TEXT值太大时,InnoDB会使用专门的“外部”存储区域进行存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储区域存储实际的值。
-->BLOB和TEXT之间的不同是BLOB类型存储的是二进制数据,没有排序规则或字符集,而TEXT类型有字符集和排序规则。
-->MySQL对BLOB和TEXT进行排序与其他类型时不同的:它只对每个列的最前max_sort_length字节而不是整个字符串做排序。
4使用枚举代替字符串类型
-->MySQL在存储枚举时非常紧凑,会根据列表值得数量压缩至一个到两个字节。
-->不建议使用数字作为枚举类型进行存储。
-->MySQL在内部会将每个值在列表中的位置保存为整数,并且在表的.frm文件中保存“数字-字符串”映射关系的“查找表”。
- 枚举字段是按照内部存储的整数而不是定义的字符串进行排序的。
- -->所以如果要绕过这种限制那么就按照需要的顺序来定义枚举列。
-->可以在查询是使用FIELD()函数显示的指定排序顺序,但这会导致MySQL无法利用索引消除排序。
5时间与日期类型
DATETME
-->这个类型能保存的值:从1001年到9999年,精度为妙。它把时间和日期封装到格式YYYYMMDDHHMMSS
的整数中,与时区无关,保存在8字节中。
TIMESTAMP
-->它保存了从1970年1月1日午夜一来的秒数,它与unix时间戳是相同的。但它只用4个字节,所以表示的范围小一点。只能表示1970到2038年。
-->MySQL中FROM_UNIXTIME()函数把unix时间戳转换为日期。UNIX_TIMESTAMP()函数将日期转换为Unix的时间戳。依赖于时区。
TIMESTAMP默认情况下,如果插入没有指定第一个TIMESTAMP列的值,MYSQL则设置这个列的值(除非在UPDATE语句中明确指定了值),TIMESTAMP列默认为NOT NULL,通常尽量使用TIMESTAMP,因为它比DATETIME空间效率更高,有时人们会将Unix时间戳存储为整数值,但是这不会带来任何收益,不推荐这么做
6位数据类型
所有的位数据,不论底层存储格式和处理方式如何,在技术上讲都是字符串类型。
BIT
-->可以使用BIT列在一列中存储一个或多个true/false值。BIT(1)定义一个包含单位的字段,BIT(2)存储2个位,因此可以推算,BIT列的最大长度为64位
-->BIT行为因存储引擎而异,MYISAM会打包存储所有的BIT列,而innoDB和Memory会为每个BIT列使用一个足够存储的最小整数类型来存储(TINYINT-->一个字节),所有并不能节省空间。
-->MySQL将bit当做字符串处理,而不是数字。当检索bit(1)时,结果是包含二进制0和1的字符串,而不是ascii码的“0”和“1”,因此会造成各种令人误解的问题,绝大多数的情况下,避免使用这一类型
如果想在bit存储空间中存储false/true值,另一个方法是创建一个可以为空的CHAR(0)列,该列可以保存空值(NULL)或者长度为零的字符串。
SET
-->可以保存很多true和false的值。SET在MySQL内部是一系列打包的位的集合来表示的。
7选择标识符
为标识列选择类型是非常重要的。
-
整数类型
整数通常是标识列的最好的选择。因为它们很快并且能使用AUTO_INCREMENT。
-
枚举类型和SET类型
不建议使用这两种当做标识列。
-
字符串类型
如果可能,应该避免使用字符串作为标识列,因为它们很消耗空间,并且通常比整数类型慢。
- 对于完全“随机”的字符串也要注意。例如:MD5(),SHA1()或者UUID()产生的字符串。这些函数生成的新值会任意的分布在很大的空间内,这会导致insert和select变得很慢。
-
原因:
- 因为插入值会随机地写到索引的不同的位置,所以使得insert语句很慢。
- select语句会变得更慢。因为逻辑上相邻的行会分布在磁盘和内存的不同的地方。
- 随机值导致缓存对所有类型的查询语句变得很差。因为缓存工作依赖访问局部性原理失效。会出现很多不命中。
8特殊类型数据
某些数据类型并不直接和内置数据类型一致。
- 低于秒级精确度的时间戳就是一个例子。
- IP存储是32位无符号整数,而不是字符串。MySQL提供INET_ATON()和INET_NTOA()函数在整数和
.表示
之间转换。
以上是关于Schema与数据类型优化的主要内容,如果未能解决你的问题,请参考以下文章