表与数据类型的优化
选择数据类型的原则
更小的通常更好:尽量使用可以正确存储数据的最小数据类型。因为更小通常更快,性能更好。
简单就好:简单数据类型通常需要更少的CPU周期。例,使用MySQL内建的类型而不是字符串来存储日期和时间;应该用整型存储IP地址,因为IP本身就是一串数字,使用点分割只是为了更容易让我们识别。
尽量避免NULL:使用NULL会让MySQL更难优化,因为可为NULL的列使得索引、索引统计和值更复杂。
整数
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT。分别使用8, 16, 24, 32, 64位存储空间。
MySQL可以为整数类型指定宽度,但是不会限制值的合法范围,只是规定一些MySQL交互工具用来显示字符的个数。
实数
FLOAT, DOUBLE, DECIMAL。FLOAT使用4个字节,DOUBLE使用8个字节。
其中FLOAT、DOUBLE使用浮点运算实现,而DECIMAL是由MySQL服务器实现其计算。
decimal(总位数, 小数点后位数)
字符串
VARCHAR, CHAR。VARCHAR为变长,CHAR为定长。当使用VARCHAR时,ROW_FORMAT不应该指定为FIXED,因为FIXED表示行长度不可变。
枚举
ENUM。底层使用整数存储,存在“数字-字符串”的映射关系表。需要注意的是排序时是按照内部整数进行排序,而不是按照字符串。在定义时,可以将枚举的项按字符串排好序,已解决排序问题。
时间
DATETIME: 1001~9999,占8个字节,与时区无关。
TIMESTAMP: 1970~2038,占4个字节,与时区有关。在插入数据时,若未指定值,则自动取当前时间作为值填充。
MySQL设计中应避免的问题
① 使用太多的列;
② 使用太多的关联:如果希望查询执行得快速且并发性好,单个查询最好在12个表内做关联。
③ 过度使用枚举;
④ 完全不使用NULL,有时候使用NULL能更好的处理业务逻辑。
范式
范式的优点:范式化的更新操作通常比反范式化要快;范式化的表更小,执行操作会更快;冗余数据更少,查询数据时更少使用DISTINCT或GROUP BY。
范式的缺点:范式化的表需要关联操作。
在实际使用中,通常混合使用范式化和反范式化。
ALTER TABLE操作
当对表使用ALTER TABLE操作时,大部分时候会导致MySQL服务中断。常用的解决方法有:
① 先在一台不提供服务的机器上执行ALTER TABLE操作,然后和提供服务的主库进行切换。
② 影子拷贝:用要求的表结构创建一张和源表无关的新表,然后通过重命名和删表操作交换两张表。
创建高性能的索引
B-Tree索引
B-Tree索引是最通用的索引类型。B-Tree索引适用于全键值、键值范围、键前缀查找、ORDER BY。
Hash索引
哈希索引,对所有索引列计算一个哈希码,并将哈希码存储在索引中,同时在哈希表中保存指向数据行的指针。哈希冲突时,使用链表保存相同哈希码的数据。
Hash索引的特点:
① 只有精确匹配索引的每一列才有效,因为Hash索引需要使用所有列计算出hash码才能找到对应的数据行。
② 无法用于排序;
③ 速度快;
④ 只能用于等值查询,不能用于范围查询。
模拟Hash索引
例如:存储大量URL时,需要根据URL进行搜索查找。这时,可以添加一个被索引的url_crc列,使用CRC32作为hash。
select id from url where url_crc=CRC32("http://") and url="http://"
全文索引
全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。
高性能的索引策略
① 索引列不能是表达式的一部分,也不能是函数的参数。应该养成简化WHERE条件的习惯,始终将索引列单独放在比较符号的一侧。
② 当需要索引很长的字符列时,可以索引开始的部分前缀字符,以节约索引空间。
③ 当创建多列索引时,需要注意索引列的顺序,应遵循前缀原则进行排序。
聚簇索引
聚簇索引不同于B-Tree索引、Hash索引,其不是一种索引类型,而是一种数据存储方式。
InnoDB的聚簇索引在同一个结构中保存了B-Tree索引和数据行。InnoDB通过主键聚集数据,如果没有定义主键,InnoDB会选择一个唯一的非空索引代替,如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。
聚簇索引的优点:① 可以把相关数据保存在一起;② 数据访问更快;③ 使用覆盖索引扫描的查询可以直接使用叶节点中的主键值。
聚簇索引的缺点:① 插入速度严重依赖于插入顺序;② 更新聚簇索引列的代价很高;③ 聚簇索引可能导致全盘扫描变慢。