高性能Mysql读书笔记#第四章

Schema与数据类型优化

转自:https://blog.csdn.net/qqqqq1993qqqqq/article/details/78110594

4.1选择优化的数据类型

①更小的通常更好。一般应该尽可能使用能正确存储数据的最小数据类型,更小的数据类型通常更快,因为他们占用更少的磁盘、内存和CPU缓存,并且处理需要的CPU周期更少。
②简单就好。整型比字符串操作代价更低。 两个例子:1、应该用MySQL内建的类型来记录日期和时间 2、应该用整型来存储IP地址(IP地址正好是32位,而且都是01值,可以转换成整形数值)
③尽量避免null。可为NULL的列使得索引、索引统计和值比较都更复杂。NULL列被索引的时候,每个索引记录都需要一个额外的字节。NULL列会使用更多的存储空间,在MySQL也需要特殊处理。(通常把可为NULL的列改为NOT NULL带来的性能提升比较小,但是如果打算在这个列上建索引,那就应该避免设计为可为NULL。)
例外:InnoDB使用单独的位(bit)存储NULL,所以对于稀疏数据(很多值为NULL)有很好的空间效率。
为数据列选择数据类型时,先确定合适的大类型:数字,字符串,时间等。datetime和timestamp可以存储相同类型的数据:日期和时间、精确到秒。然而timestamp只使用datetime一半的存储空间,并且会根据时区进行变化,具有特殊的自动更新能力。但是timestamp允许的时间范围要小的多,有时候它的特殊能力会成为障碍。

4.1.1 整数类型

存储整数的类型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT。分别使用的存储空间为8,16,24,32,64位存储空间。
整数类型有可选的UNSIGNED属性,表示不允许负值,这大致可以使整数的上限提升一倍。
MySQL可以为整数类型指定宽度,例如INT(11),对于大多数应用这是没有意义的。它不会限制值的合法范围。只是规定了MySQL的交互工具(客户端)用来显示字符的个数。对于存储和计算来讲INT(1)和INT(20)是一样的。

4.1.2 实数类型

float和double类型支持使用标准的浮点运算进行近似计算。(float4字节,double8字节)
DECIMAL类型用于存储精确的小数。在MySQL5.0+版本中DECIMAL类型支持精确计算。(每4个字节存储9位数字,因为还是转化为2进制来存储,4字节也就是32位,最大的位数是10位)
浮点和DECIMAL类型都可以指定精确度。对于DECIMAL列,可以指定小数点前后所允许的最大位数。这会影响列的空间消耗。

4.1.3 字符串类型(感觉比较常问到)

VARCHAR

用于存储变长字符串,使用额外的存储空间来存储字符串长度。需要1或者2个额外字节记录字符串长度。如果列的最大长度小于或者等于255,则值需要1个字节表示,否则使用2个字节。
在5.0以上版本,会保留末尾的空格。
如果UPDATE时使得行比原来更长,这时需要额外的工作,MyISAM会将行拆分成不同的片段存储,InnoDB则需要分裂页来使行可以放进页内。会保留存储字符串的末尾空格。
VARCHAR适用:1、字符串列的最大长度比平均长度大很多;2、列更新很少,所以碎片不是问题;3、使用了像UTF8这样负责的字符集,每个字符使用不同的字节数进行存储。

CHAR

CHAR:定长(也就是分配固定的空间),会删除字符串末尾空格
CHAR适合:1、存储定长或长度接近的数据;2、对于经常变更的数据CHAR不容易产生碎片;3、对于非常短的列CHAR在存储空间上更有效率
※VARCHAR(1)比CHAR(1)需要更多空间,因为VARCHAR还需要一个字节来记录长度的额外字节

BLOB和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字节而不是整个字符串做排序。

ENUM

使用枚举(ENUM)代替字符串。对于枚举类型在表.frm文件中会保存“数字-字符串”的映射关系,行内存储的是值在列表中的位置(从1开始),排序的时候是按照列表中声明的顺序,使用枚举类型可以减少表的大小。

枚举类型最大的缺点在于增加或删除字符串的时候必须使用ALTER TABLE, 除非只是在末尾添加字符串,不然需要重建整个表。枚举列在进行关联查询的时候,如果和CHAR OR VARCHAR关联,性能会比较差甚至不如直接用字符串,但是枚举和枚举关联,性能不错。在某些情况下,即使可能出现ENUM和VARCHAR关联的情况这也是值得的,因为可以减少I/O。

4.1.4 时间类型

DATETIME

这个类型能保存的值:从1001年到9999年,精度为妙。它把时间和日期封装到格式YYYYMMDDHHMMSS的整数中,与时区无关,保存在8字节中。

TIMESTAMP

它保存了从1970年1月1日午夜一来的秒数,它与unix时间戳是相同的。
但它只用4个字节,所以表示的范围小一点。只能表示1970到2038年。
MySQL中FROM_UNIXTIME()函数把unix时间戳转换为日期。
UNIX_TIMESTAMP()函数将日期转换为Unix的时间戳。
依赖于时区。

位数据类型

BIT: BIT列最长64位。BIT(64)需要8个字节来存储。MySQL把BIT当作字符串类型而非数字类型,所以查询BIT列的时候得到的是所存储的二进制值作为ASCII码对应的字符串,如果用BIT列和其他数字比较或计算,那么查询到的是数字。这个相当费解,建议谨慎使用。
SET: 在MySQL内部以一系列打包的位的集合来表示,可以有效的利用存储空间,并且有FIND_IN_FIELD(), FIELD()这样的函数可以在查询时使用。主要缺点是改变列的定义代价比较大。
一种替代SET的方案就是用一个整数包装一系列的位。类似于Linux文件系统的权限管理那样。

特殊类型
IP地址: 通过INET_ATON()和INET_NTOA()函数在IP地址和无符号整数之间做转换。

范式和反范式

范式优点:
范式化的更新操作比反范式化要快
当数据较好地范式化的时候,就只有很少或者没有重复数据,所以只需要修改更少的数据
范式化的表通常更小,可以更好的放在内存里,所以执行操作会更快
很少有多余的数据意味着检索列表数据时更少需要DISTINCT和GROUP BY这样的语句。
范式缺点:
通常需要关联
代价昂贵,也可能是一些索引策略无效
反范式优点:
不需要关联查询
反范式缺点:
数据冗余
更新和插入操作需要做更多
缓存表和汇总表
这个感觉就看具体需求了,对于缓存或者汇总的数据实时性要求有多高,然后采取不同的策略。

影子表:是指在一张真是表“背后”创建同样的表,然后建好之后通过原子的重命名操作切换。
mysql> DROP TABLE IF EXISTS my_summary_new, my_summary_old;
mysql> CREATE TABLE my_summary_new LIKE my_summary;
mysql> RENAME TABLE my_summary TO my_summary_old, my_summary_new TO my_summary;

物化视图

MySQL并不支持物化视图,可是使用开源工具Flexviews来实现。

加快ALTER TABLE的速度

ALTER TABLE一般都很慢,操作将导致MySQL服务中断。一般来说是会新建个表,然后从旧表读取数据插入到新表中,这样效率很慢。
但并不是所有的都这么慢,比如修改一个列的默认值有两种办法:
①:mysql> ALTER TABLE film MODIFY COLUMN rental_duration TINYINT(3) NOT NULL DEFAULT 5;
②:mysql> ALTER TABLE file ALTER COLUMN rental_duration TINYINT(3) NOT NULL DEFAULT 5
第一种方法是通过上面所说的读取插入的方式。 第二种方法会直接修改.frm文件不涉及数据,所以很快。

下面有一些修改表的操作是不需要重建表的:
移除一个列的AUTO_INCREMENT属性
增加、移除或更改ENUM和SET常量。如果移除的是已经有行用到的,查询将返回一个空字符串。
基本思路是为想要的表结构创建一个新的.frm文件,然后替代已有的那个:
创建相同结构的表,并进行修改
执行FLUSH TABLES WITH READ LOCK。这将关闭所有正在表,并且禁止任何表被打开。
交换.frm文件
执行UNLOCK TABLES释放锁。
为InnoDB表增加索引的时候也可以尝试一种比较骇客的方法(官方并不支持,注意备份数据):

用需要的表结构创建一张表,但是不包括索引:
载入数据到表中以构建.MYD文件
按照需要的接口创建另外一张空表,这次包含索引。这会创建需要的.frm和.MYI文件。
获取读锁并刷新表。
重命名第二张表的.frm和.MYI文件,让MySQL以为是第一张表的文件。
释放读锁。
使用REPAIR TABLE来重建表的索引。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章