Schema(范式与反范式)与数据类型优化

选择正确数据类型的依据:
1、更小的通常更好,因为它们占用更少的磁盘、内存和CPU缓存。
2、简单的数据类型
2、避免使用null,通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。可为NULL的列使得索引、索引统计和值比较都更为复杂。

整数类型

TINYINT、SMATLLINT\MEDIUMINT、INT、BIGINT分别使用8、16、24、32、64位存储空间。MYSQL可以为整数类型指定宽度,但是对大多数应用没有意义,它只是规定了某些数据库交互工具显示的字符个数,在存储和计算中它们和不加列宽是一样的效果。

实数类型

DECIMAL、FLOAT、DOUBLE。在数据量比较大的时候,将小数乘以指定倍数,并使用BIGINT存储,这样可以避免浮点存储计算不准确和DECIMAL精确计算代价高的问题。

字符串类型

VARCHAR(10)为变长字符串,最大长度为10,需要11个存储空间,10个做字符存储空间用,1个做记录长度用。如果最大长度大于255则需要用两个字节记录长度,如VARCHAR(1000)的列则需要1002个字节。VARCHAR在update时面临空间需要增长的问题,这需要额外的工作。下面的情况使用VARCHAR是合适的:字符串列最大长度比平均长度大很多;列的更新很少,所以碎片不是问题;使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。
CHAR适合存储很短的字符串,或者所有值都接近同一个长度。例如,CHAR非常适合存储密码的MD5值。对于经常变更的数据,CHAR也比VARCHAR更好,因为定长不容易产生碎片。CHAR比VARCHAR少一些记录长度的字节。当存储CHAR的时候,MYSQL服务器会删除所有的空格。

VARCHAR(5)和VARCHAR(200)存储’hello’的空间开销是一样的,但是更长的列会消耗更多的内存,因为MySQL通常会分配固定大小的内存块来保存内部值。

BLOB和TEXT类型

BLOB和TEXT都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。MySQL把每个BLOB和TEXT当作一个独立的对象处理,InoDB会使用专门的外部存储区域来进行存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储区域存储实际的值。BLOB和TEXT家族之间仅有的不同是BLOB存储的是二进制数据,没有排序规则或字符集,而TEXT类型有字符集和排序规则。MySQL对BLOB和TEXT列进行排序与其他类型不同:它只对每个列的最前max_sort_length字节而不是整个字符串排序。如果只需要排序前面一小部分字符,则可以使用ORDER BY SUSTRING(column, length)
减小max_sort_length。MySQL不能将BLOB和TEXT列全部长度的字符串进行索引,也不能使用这些索引消除排序。

使用枚举类型替代字符串

可以使用枚举列代替常用的字符串类型。可以让表的大小缩小。

日期和时间类型

DATETIME:这个类型能保存大范围的值,从1001年到9999年,精度为秒。与时区无关,仅保留文本表示的日期和时间。
TIMESTAMP:只能表示从1970到2038年。保存了从1970年1月1日午夜(格林尼治标准时间)以来的秒数。
除了特殊行为之外,通常也应该尽量使用TIMESTAMP,因为它比DATETIME空间效率更高。

位数据类型

MySQL把bit当作字符串类型,而不是数字类型。例如存储一个值‘00111001’到BIT(8),检索它时.得到的内容是字符码为57的字符串。也就是说得到ASCII码为57的字符’9’。这是相当令人费解的,所以我们认为应当谨慎使用BIT类型。

选择标识符技巧

为标识列(标识某行的列,主键是一种标识列)选择合适的数据类型非常重要。一般来说更有可能用标识列与其他值进行比较,或者通过标识列寻找其他列。所以为标识列选择数据类型时,应该选择跟关联表中对应列一样的类型。
1.整数类型
整数类型是标识列最好的选择,因为他们很快并且可以使用AUTO_INCREMENT。
2.ENUM和SET类型通常是一个糟糕的选择。
3.字符串,如果可能应该避免使用字符串作为标识列。1.空间大2.MyISAM对字符串使用压缩索引,引起性能下降。3.完全随机的字符串分布在很大的空间内,会导致INSERT和SELECT变得很慢:插入值随机写道索引的不同位置,INSERT语句变慢,页分裂,磁盘随机访问以及聚簇存储引擎产生聚簇索引碎片。逻辑上的相邻分布在磁盘和内存的不同地方。随机值导致缓存对所有类型的查询语句都很差,因为会使得缓存赖以工作的访问局部性原理失效。
如果存储UUID,则应该移除"-"符号;或者更好的做法是,用UNHEX()函数转换UUID值为16字节的数字,并且存储在一个BINARY(16)列中。检索时可以通过HEX()函数来格式化为十六进制格式。UUID生成的虽然分布不均匀,但还是有一定的顺序的。

IP地址存储方式

IP实际上是32位无符号整数,不是字符串。用小数点将地址分成四段只是为了让人们阅读容易。所以应该用无符号整数存储IP地址。MYSQL提供INET_ATON()将‘192.13.21.2’这样的地址转换为无符号整数,提供INET_NTOA()将数字转换为字符串

MySQL schema设计中的陷阱

1.太多的列,MySQL的存储引擎API工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲中将编码过的列转换成行数据结构的操作代价是非常高的。
2.太多的关联,MySQL限制了每个关联操作最多只能有61张表,单个查询最好在12个表以内做关联。
3.全能枚举,如果要往枚举列新增一个项,则必须使用ALTER TABLE,这个是阻塞的,代价大。

范式与反范式

范式带来好处
1.范式化很少或者没有重复数据,只需要修改更少的数据。
2.范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快。
3.很少的多余数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句。在非范式化的结构中
范式带来的坏处
1.查询需要关联表

你可能感兴趣的:(MySQL)