0%

MySQL 性能-库表

数据类型

更小通常更好 选择不会超过范围的最小类型

简单更好 简单数据类型操作代价低

尽量避免 NULL 值 索引会变得复杂,但不要极端

整数类型

类型 存储空间
tinyint 8 bit
smallint 16 bit
mediumint 24 bit
int 32 bit
bigint 64 bit

UNSIGNED 属性不影响性能。

整数计算一般(某些聚合函数使用 decimal double)使用 64 位,与类型定义和环境无关。

为整数类型指定宽度(int(10))不会改变存储和计算的方式,不会限制值的合法范围。

实数类型

类型 存储空间
float 4 byte
double 8 byte
decimal 每 4 byte / 9 个数字
小数点 1 byte

浮点计算内部使用 double 类型。

decimal 类型计算由 MySQL 自身实现,速度不如浮点;可以用来存储比 bigint 大的整数;数据量大时考虑用 bigint 代替 decimal 计算(乘以倍数后存储)。

字符串类型

注意字符串长度定义是字符数,多字节字符集需要更多存储空间

varchar 和 char

varchar 使用额外字节记录字符串的长度(<=255 一字节 否则两字节),如 varchar(1000) 需要 1002 字节。若 update 使得字符串变长,MyISAM 将行拆成不同的片段存储,InnoDB 则分裂页使行可以放入。用更长的列存储短字符串虽然空间开销一样,但会消耗更多内存。

  • 字符串列的最大长度比平均长度大很多;
  • 列的更新很少;
  • 使用了每个字符字节数不同的复杂字符集(如 UTF-8);

char 会删除值末尾的空格,并根据需要填充空格以方便比较。因为定长,不宜产生碎片,没有额外字节。

  • 较短字符串(如 char(1) Y/N);
  • 经常变更的数据;
  • 所有值接近一个长度;

blob 和 text

blob 是 smallblob 的同义词,采用二进制方式存储,没有排序规则或字符集;text 是smalltext 的同义词,采用字符方式存储,有排序规则和字符集(两者仅有的不同)。

blob 或 text 值太大时,每个值会通过行内 1~4 个字节的指针指向存储区域中实际的值。

enum

MySQL 内部将每个值在列表中的位置保存为整数,并在 .frm 文件中保存映射表。

enum 按照定义时的顺序(即存储的整数)而非字符串进行排序。显示指定:

1
select e from enum_table order by field(e, 'a', 'b', 'c');

某些情况下,char/varchar 列与枚举列进行连接可能比直接连接 char/varchar 列更慢。(采用整数主键而避免采用基于字符串的值进行关联)。

日期和时间类型

类型 存储空间 时区 格式
datetime 8 bit (1001 - 9999) 无关 YYYYMMDDHHMMSS 整数
timestamp 4 bit (1970 - 2038) 依赖 UNIX 时间戳

比秒更小的粒度可以考虑 bigint (时间戳)或 double (秒后小数部分)。

位数据类型

bit 在 MySQL 中作为字符串类型,而非数字类型;但在数字上下文中将是位字符串转换成的数字:

1
2
3
4
5
create table bittest(a bit(8));
insert into bittest values(b'00111001');
select a, a+0 from bittest;
-- a 9
-- a+0 57

set 多选字符串数据类型,适合存储“多个值”。

设定set的格式:
  字段名称 SET(‘选项1’, ‘选项2’, …, ‘选项n’)

set 的每个选项值也对应一个数字,依次是1,2,4,8,16…,最多有64个选项。
使用的时候,可以使用 set 选项的字符串本身(多个选项用逗号分隔),也可以使用多个选项的数字之和(比如:1+2+4=7)。


范式

范式优缺点

  • 更新操作比范式化快
  • 重复数据很少或没有,修改更少的数据
  • 表更小,执行操作更快
  • 检索时更少需要 distinct 或 group by 语句
  • 需要关联,产生额外代价
  • 列存放在不同的表中,可能使一些索引无效

反范式优缺点

  • 避免关联,顺序 I/O (与引擎有关)。
  • 使用更有效的索引
  • ……略

混用范式化和反范式化

从父表冗余一些数据到子表以方便排序。

缓存衍生值,避免性价比不高的子查询。


缓存表和汇总表

更快的读,更慢的写

缓存表(Cache Table)指那些包含能够轻松从Schema中获得的数据的表(但每次获取的速度慢),即表中的数据是逻辑冗余(Logically Redundant)。

汇总表(Summary/Roll-up Table)是说包含通过聚合函数得到的数据的表,例如表中数据是通过GROUP BY得到的。对优化搜索和检索查询语句很有效。

最常见的场景就是报表等统计工作。生成这些统计数据要扫描大量数据,实时计算成本很高且很多时候没有必要。而且查询这些数据还要加大量组合索引才能提高性能,然而这些索引又会对平时的更新和插入等操作造成影响。于是常用技术就是添加中间表到其他引擎(利用MyISAM更小的索引和全文检索能力),甚至其他系统(Lucene或Sphinx)。

计数表

解决独立表并发问题可以建多行,根据id随机更新,然后统计时 sum() 。

1
2
3
4
5
6
7
8
CREATE TABLE hit_counter(
slot tinyint unsigned not null primary key,
cnt int unsigned not null
) ENGINE=InnoDB;

UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND() * 100;

SELECT SUM(cnt) FROM hit_counter;

可以按天或小时单独建行,旧时间可定时任务合并到统一的一行。

1
2
3
4
5
6
CREATE TABLE daily_hit_counter(
day date not null,
slot tinyint unsigned not null primary key,
cnt int unsigned not null,
primary key(day, slot)
) ENGINE=InnoDB;

加速 alert table 操作

先禁用(删除)非唯一索引,导入数据之后重新启用索引。