《高性能MYSQL》——选择优化的数据结构

选择优化的数据类型

在选择列的数据类型时,应该遵循以下原则

1.更小的通常更好

一般来说,尽量使用能够正确存储和表示数据的最小数据类型。更小的数据类型通常更快,因为它们占用的磁盘、内存和CPU缓存的空间更少,并且处理时需要的CPU周 期也更少。

2.简单为好

简单数据类型的操作会需要更少的CPU周期,比如说要对某列进行比较操作时,类型为整型的列比类型为字符型的列代价更低,因为字符集和排序规则使字符型数据的比较相对复杂。

3.尽量避免存储NULL

通常情况下最好指定列为NOT NULL,除非明 确需要存储NULL值。如果查询中包含可为NULL的列,对MySQL来说更难优化,因 为可为NULL的列使得索引、索引统计和值比较都更复杂。可为NULL的列会使用更 多的存储空间,在MySQL里也需要特殊处理。

DATETIME和TIMESAMP列可以存储相同类型的数据:时间和日期,精确到秒。 然而TIMESTAMP只使用DATETIME一半的存储空间,还会根据时区变化,而且具有特殊 的自动更新能力。但是,TIMESTAMP允许的时间范围要小得多

有两种类型的数字:整数(whole number)和实数(real number,带有小部分的数字)

整数类型

如果存整数,可以使用:TINYINT、SMALLINT、 MEDIUMINT、INT或BIGINT。它们分别使用8、16、24、32和64位存储空间。

你的选择决定了MySQL在内存和磁盘中保存数据的方式。然而,整数计算通常使用64位的BIGINT整数。(一些聚合函数是例外,它们使用DECIMAL或DOUBLE进行计算。)

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

实数类型

实数是带有小数部分的数字。

浮点类型通常比DECIMAL使用更少的空间来存储相同范围的值。FLOAT列使用4字节的

存储空间。DOUBLE占用8字节,比FLOAT具有更高的精度和更大的值范围。与整数类型

一样,你只能选择存储类型;MySQL会使用DOUBLE进行浮点类型的内部计算。

对于实数数据类型的选择,尽量只在对小数进行精确计算时才使用DECIMAL,比如价钱。

由于DECIMAL精确计算代价高,所以在大容量场景下也可以使用BIGINGT来代替DECIMAL,将需要存储的货币单位根据小数的位数乘以相应的倍数即可。

字符串类型

VARCHAR和CHAR值通常是如何存储在磁盘上的

VARCHAR用于存长度可变的字符串(比固定长度的类型更加省空间),它除了存这个字符串以外还会使用1个字节或者2个字节去存这个字符串的长度(如果列的最大长度小于或等于 255字节,则只使用1字节表示,否则使用2字节),并且VARCHAR类型不会把数据后面跟的空格删除。

注意:InnoDB可以将过长VARCHAR值存储为BLOB

CHAR长度是固定的,MySQL总是为定义的字符串长度分配足够的空间。在一个CHAR(5)的列中存储字符串'abc',实际上会存储为'abc ',占用5个字符的空间,右侧用空格填充。当存储 CHAR值时,MySQL删除所有尾随空格。CHAR适合存储非常短的字符串(Y和N,yes和no),或者适用于所有值的长度都几乎相同的情况(MD5加密后的密码)

BINARY和VARBINARY类型

有BINARY和VARBINARY,它们存储的是二进制字符串,就是 0x616263 这种二进制数据。

同样的,BINARY会删除尾随空格,VARBINARY不会删除尾随空格。

BINARY是固定长度,VARBINARY是可变长度。

注意:MySQL填充BINANRY用的是\0(零字节)而不是空格

BLOG和TEXT类型

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

当BLOB和TEXT值太大时,InnoDB会使用独立的“外部”存储区域,此时每个值在行内需要1~4字节的存储空间,然后在外部存储区域需要足够的空间来存储实际的值

MySQL对BLOB和TEXT列的排序与其他类型不同:它只对这些列的最前max_sort_length

字节而不是整个字符串做排序。如果只需要按前面少数几个字符排序,可以减小

max_sort_length服务器变量的值。

注意:MySQL不能将BLOB和TEXT数据类型的完整字符串放入索引,也不能使用索引进行排

序。

日期时间类型

DATETIME

这种类型可以保存大范围的数值,从1000年到9999年,精度为1微秒。它以

YYYYMMDDHHMMSS格式存储压缩成整数的日期和时间,且与时区无关。这需要8

字节的存储空间。

默认情况下,MySQL以可排序、无歧义的格式显示DATETIME值,例如,2008-01-

16 22:37:08。这是ANSI表示日期和时间的标准方式。

TIMESTAMP

顾名思义,TIMESTAMP类型存储自1970年1月1日格林尼治标准时间(GMT)午夜以

来经过的秒数——与UNIX时间戳相同。TIMESTAMP只使用4字节的存储空间,所以

它的范围比DATETIME小得多:只能表示从1970年到2038年1月19日。

创建高性能的索引

索引是一种数据结构

索引的类型

在MySQL中,索引是在存储引 擎层而不是服务器层实现的。不同的存储引擎就有不同的索引类型

B-TREE

B-tree:所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同

示例:B-tree一个节点和其对应的叶子节点

索引如何工作

B-tree索引能够加快数据访问的速度,这是因为有了索引,在查询某些条件的数据时,存

储引擎不再需要进行全表扫描。而是从索引的根节点(图中并未画出)开始进行搜索,根

节点的槽中存放了指向子节点的指针,存储引擎根据这些指针向下层查找。通过比较节点

页的值和要查找的值可以找到合适的指针进入下层子节点,这些指针实际上定义了子节点

页中值的上限和下限。最终存储引擎要么找到对应的值,要么该记录不存在。

B-TREE里面的数据按照什么顺序排放?

B-TREE是按照索引列中的数据大小顺序存储的,所以很适合按照范围来查询。

如果索引有多个列,就会按照列的顺序进行排序,对于2行数据,如果在索引中的第一个列这2行数据相对,就开始比较第二列,,,依次进行下去。

自适应哈希索引

InnoDB存储引擎有一个被称为自适应哈希索引的特性。当InnoDB发现

某些索引值被非常频繁地被访问时,它会在原有的B-tree索引之上,在内存中再构建一个

哈希索引。

索引起作用的情况:

1.全值匹配

2.匹配最左前缀

3.匹配列前缀,这个解释一下,就是只匹配某一列的值的开头部分

4.匹配范围值,比如一个索引有三列(姓,名,出生日期),那么这个索引可用于查找姓在Allen和Barrymore之间的人。这里也只使用了 索引的第一列。

5.精确匹配某一列而范围匹配另外一列,前面提到的索引也可用于查找所有姓为Allen,并且名字是字母K开头(比如Kim、 Karl等)的人,即第一列last_name是全匹配,第二列first_name是范围匹配。

6.只访问索引的查询

需要提到的是,在使用ORDER BY语句时,索引也能起作用

B-tree索引的限制

如果不是按照索引的最左列开始查找,则无法使用索引。

不能跳过索引中的列

如果查询中有某列的范围查询,则其右边所有列都无法使用索引优化查找