一、数据类型

1、MySQL支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要。不管存储哪种类型的数据,下面几个原则都有助于做出更好的选择。

1.1更小的通常更好 一般情况下,应该尽量使用可以正确存储数据的最小数据类型。因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少。

1.2简单就好 简单数据类型的操作通常需要更少的CPU周期。例如,整型比字符操作代价更低,因为字符集和校对规则(排序规则)使字符比整型更复杂。

1.3尽量避免NULL 如果查询中包含可为NULL的列,对MySQL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。当可为NULL的列被索引时,每个索引记录需要一个额外的字节。

2、整数类型

mysql培训表设计 数据库mysql培训_字符串

 

 

在存储金融数据时,可以考虑使用bigint代替decimal,将需要存储的货币单位根据小数的位数乘以相应的倍数即可。这样可以避免浮点存储计算不准确和decimal精确计算代价高的问题

3、字符串类型 char()

用于保存固定长度的字符串,长度最大为255,比指定长度大的值将被截断,比指定长度小的值会用空格填补。 varchar()用于保存可变长度的字符串,长度最大为65535(MySQL官方手册中定义的65535长度是指所有varchar列的长度总和),只存储字符串实际需要的长度,但是会用1~2个字节来存储值得长度。如果列的最大长度小于或255,则使用1字节,否则就是2字节。 char和varchar与字符编码也有密切联系,GBK占用2个字节,UTF8占用三个字节,UTF8MB4占用四个字节。

3.1 GBK字符集

mysql培训表设计 数据库mysql培训_数据_02

解析:因为varchar类型长度大于255,所以要用2字节存储值的长度。 计算公式:(65535-2)/ 2= 32766.5,也即是说不能大于32767

mysql培训表设计 数据库mysql培训_字符串_03

 

 

 3.2 UTF8字符集

mysql培训表设计 数据库mysql培训_MySQL_04

解析:因为varchar类型长度大于255,所以要用2字节存储值的长度。 计算公式:(65535-2)/ 3= 21844.3,也即是说不能大于32767

3.3 UTF8MB4字符集

mysql培训表设计 数据库mysql培训_MySQL_05

解析:因为varchar类型长度大于255,所以要用2字节存储值的长度。 计算公式:(65535-2)/ 4= 16383.2,也即是说不能大于32767

例子: CREATE TABLE `t5` ( `v` varchar(9) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

mysql> select * from t5;

+-----------------------------+

| 一二三四五 |

| 一二三四五六 |

| 一二三四五六七 |

| 一二三四五六七八 |

| 一二三四五六七八九 |

| 111111111 |

| aaaaaaaaa |

+-----------------------------+

7 rows in set (0.00 sec)

mysql> insert into t5 values ('一二三四五六七八九十');

ERROR 1406 (22001): Data too long for column 'v' at row 1

扩展: InnoDB存储引擎表是索引组织的,即B+tree的结构,这样每个页中至少应该有两条行记录。因此, 如果页中只能存放下一条记录,那么会自动将行数据存放到溢出页中。 InnoDB存储引擎的页为16KB,即16384字节,是不能存放65532字节的,因此,在一般情况下,InnoDB存储引擎的数据都是存放在页类型为B-tree node中。但当发生行溢出时,数据存放的页类型为Uncompress BLOB页中。 在多字节字符集的情况下,char和varchar的实际行存储基本是没有区别的。

4 BLOB和TEXT

专为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。与其它类型不同,MySQL把每个BLOB和TEXT值当作一个独立的对象处理。存储引擎在存储时通常会做特殊处理。当BLOB和TEXT值太大时,InnoDB会使用专门的“外部”存储区域来进行存储,此时每个值在行内需要1~4个字节存储一个指针,然后在外部存储区域存储实际的值。 尽量避免使用BLOB和TEXT类型。如果实在无法避免,有一个技巧是在所有用到BLOB字段的地方都使用SUBSTRING(column,length)将列值转换为字符串(在order by 子句中也适用),这样可以使用内存临时表。但是要确保截取的字符串足够短,不会使临时表的大小超过max_heap_table_size或tmp_table_size,超过以后MySQL会将内存临时表转换为MyISAM磁盘临时表。

5 日期和时间类型

DATETIME和TIMESTAMP 通常尽量使用TIMESTAMP,因为它比DATETIME空间效率更高。

二、SQL优化

mysql培训表设计 数据库mysql培训_MySQL_06

 

1、InnoDB引擎的索引类型

mysql培训表设计 数据库mysql培训_字符串_07

 

 

 SQL优化-B+树索引

                                                                              

mysql培训表设计 数据库mysql培训_数据_08

 

 

 

mysql培训表设计 数据库mysql培训_mysql培训表设计_09

 

 

 

B+树是由B树和索引顺序访问方法演化而来的,是专门为磁盘和其他直接存取辅助设备而设计的一种平衡查找树。

在B+树中,所有记录都是按照键值的大小顺序存放在同一层的叶子节点中,各叶子节点之间通过指针进行连接。

何为B+树索引?

其实就是B+树结构在数据库中的实现。 它的一个特点就是扇出性比较高,因此树的高度较低;比如:2~3层的树,查找某一键值的行记录时,最多只需要2~3次I/O,这确保了索引的效率。

容易忽略的问题!

这里有一个容易忽略的问题:B+树索引并不是指向一个给定键值的具体行,而是找到该数据行所在的数据块(或者称为页),然后将该数据块读入内存,并在内存中查找,最后得到要查找的数据。

如何使用B+树索引?

只有当键值的选择性(离散度)较高,且只读取表中很少一部分记录时,使用B+树索引才有意义。

SQL优化-索引使用

不是所有字段都适合建索引!

索引不是越多越好!

有了索引优化器不一定会使用!

创建、使用联合索引时,是要特别注意字段顺序的!

多个索引时,优化器选择使用哪一个?

例:表student,字段s_no主键,s_name普通索引,………..

select * from student;

--走主键索引,辅助索引得不到全部数据。

SELECT s_no,s_name FROM student;

--走辅助索引即可得到全部数据,一个辅助索引页可以比主键页存放更多行记录。

select s_no,s_name from student order by s_no;

--走主键索引,主键本来就是顺序存储的,避免了排序操作。

PRIMARY KEY ('CID'), UNIQUE KEY 'IDX_CN_CNAME' ('CNAME'), KEY 'IDX_CN_CID_UID' ('CID', 'CUSTOMERID'), KEY 'IDX_CN_PRODTYPE' ('PRODTYPE'), KEY 'IDX_CN_P_C' ('PRODTYPE','CNSTATUS'), KEY 'IDX_CN_UID' ('CUSTOMERID')

cid是主键,可以唯一确定一条记录,那么再以cid和customerid创建联合索引实际上是多余的;

创建了prodtype和cnstatus复合索引,再创建prodtype的索引也是多余的;

SQL优化-行级锁

InnoDB引擎是支持行锁的,行级锁没有相关的锁开销,可以同时得到并发性和一致性。

三种行锁算法设计:

Record Lock--记录锁,锁定单个行记录;

Gap Lock--间隙(区间)锁,锁定一个范围,但不包含记录本身,即不包括边界值;

Next-Key Lock--Gap Lock+Record Lock组合,缺省方式,不但锁定一个范围,并且锁定记录本身;它是一个半开半闭的区间,并且是上届闭,下届开 ,可能的情况包括:(-∞,10]、(10,20]、(20,+∞)

InnoDB引擎的行锁是基于索引实现的!

mysql培训表设计 数据库mysql培训_mysql培训表设计_10

 

当索引不存在时,或者索引存在,而优化器没有采用时,InnoDB则放弃行锁而采用表锁,这显然扩大了锁的粒度,大大增加了阻塞产生的几率,降低了数据库的并发性能。

 

mysql培训表设计 数据库mysql培训_mysql培训表设计_11

 

 优化器选择使用不同的索引,行锁的作用范围也不一样,所以即使修改不同行记录,只要优化器采用的那个索引的键值一样,也会出现阻塞情况。

mysql培训表设计 数据库mysql培训_数据_12

 

 有一点需要特别注意:间隙锁锁定的是一个范围,而不是一系列索引键值,不管记录是否真实存在,只要属于这个范围,都会被锁定,从而产生阻塞。