数据类型
整数与小数类型
整数类型有如下几种:
TINYINT(1个字节),SMALLINT(2个字节),MEDIUMINT(3个字节),INT(4个字节),BIGINT(6个字节)。
小数(实数)类型有如下几种:
FLOAT4个字节)、DOUBLE(8个字节)、DECIMAL(占用字节更多)。
DECIMAL(n,m)表示仅允许保留m位小数;n表示小数点左右两边数字总和。也就是说只允许n-m个整数位。
字符串类型
varchar是使用最频繁的字符串类型,它除了维护字符串还维护了一个或者两个字节用来记录长度。varchar(n),n代表单个字符的个数
当我们设置varchar(5)或者varchar(100)来存储 “mysql”,哪个会更好呢?当然是varchar(5)更好,因为varchar(100)即使之存储5个字符的字符串,也会分配100个字符的内存空间,特别是当使用临时表会更不好。
char用来存储较小的字符串 char(n)代表可以存储n个字符的字符串。
blob 与text
这两种类型是用来存储较大字符串的类型,与其他类型不同,它们的排序只按照最前边max_sort_length个字符进行排序,而不是按照全部字符排序。因此如果只需要按照较小的字符排序,可以缩小max_sort_length的设定。或者使用 order by substring( column,length)进行排序。
enum
用时可以使用 enum(“string1”,”string2”,”string3”)代替varchar\char等字符串类型。
enum类型对字符,实际是使用整数进行存储的,并且当对enum列排序也是按照实际存储的整数值排序。适合存储如有序的状态,性别等等。
比如,我们新增一个enum类型的列,并按照主键id依次顺序插入:
ALTER TABLE USER ADD enumType ENUM("apple","banana","orange");
ALTER TABLE USER ADD enumType ENUM("apple","banana","orange");
UPDATE `user`.`user` SET `enumType` = 'apple' WHERE id=1;
UPDATE `user`.`user` SET `enumType` = 'banana' WHERE id=2;
UPDATE `user`.`user` SET `enumType` = 'orange' WHERE id=3;
SELECT id,(enumType+0) AS a FROM USER ;
OUTPUT:
id enumType
1 1
2 2
3 3
可以看到,插入的 “apple”,”banana”,”orange”分别使用 1,2, 3进行存储,也就是按照enum设定的顺序。当然对这个enum列的排序也是按照数字排序。
注意:因此我们在使用enum类型的时候,切记不要存储 如 enum(“10”,”29”,”42”,”99”)这有 的字符串类型的数字,以避免产生不必要的混淆!
enum类型
优点:更紧凑的存储,更加节省空间;
不足:当enum类型的列 与 varchar类型的列进行关联时比两个varchar进行关联慢一些。
日期与时间
DATETIME
datetime 用来表示日期,范围从1001年到9999年,精确到秒:YYYYMMDDHHMMSS,占用8个字节。这种类型与时区无关。
TIMESTAMP
从1970.1.1以来的描述,跟UNIX时间戳相同。
占用4个字节,也是精确到秒,但是范围要比DateTime小很多,1970~2038。
另外,这种类型默认not null,首次插入会自动用当前时间填充。
FROM_UNIXTIME()可以把时间戳转为日期。
UNIX_TIMESTAMP()可以把日期转为时间戳。
对于比秒更小的粒度:目前暂无支持,可以使用bigint存储更小的时间戳。
数据类型优化技巧
1、数据类型更小通常更好,数据类型越简单越好
2、数值操作比字符操作快,小类型的处理速度比大类型快
3、尽量避免使用NULL,要是有必要用NULL,那也可考虑使用0来进行代替
4、IP用int存:inet_aton()、inet_ntoa()
范式设计
第一范式:要求有主键,并且要求每一个字段原子性不可再分
第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
第三范式:所有非主键字段和主键字段之间不能产生传递依赖
第一范式:要求有主键,并且要求每一个字段原子性不可再分
第一范式很好理解,首先要确保每一行都有主键存在,另外每一列都要有不可拆分的业务对象。
-- -违反范式一 userContact 中是“手机号,qq号”
"cid" "userContact"
"2" "15472152456,502327342"
"3" "13676574456,7702322"
修改为:
"cid" "phone" "qqNumber"
"1" "15472152456" "502327342"
第二范式:要求所有非主键字段完全依赖主键,不能产生部分依赖
即满足第一范式前提,当存在多个主键的时候,才会发生不符合第二范式的情况。比如有两个主键,不能存在这样的属性,它只依赖于其中一个主键,这就是不符合第二范式。通俗理解是任意一个字段都只依赖表中的同一个字段。(涉及到表的拆分)
第三范式:所有非主键字段和主键字段之间不能产生传递依赖
请看下边的例子:
"cid" "role" "phone" "qqNumber" "level"
"1" "programmer" "15472152456" "502327342" "6"
"2" "manager" "15372152456" "534232" "2"
"3" "manager" "15372152436" "5023272" "3"
这个设计就违反了第二范式,因为level字段依赖于role,role依赖于cid:
cid 为1的员工 programmer 角色 级别为6;
cid 为2的员工 manager级别 级别为2;
cid 为3的员工 manager级别为3
-- - 符合第二范式:
"cid" "phone" "qqNumber"
"1" "15472152456" "502327342"
"2" "15372152456" "534232"
"3" "15372152436" "5023272"
"cid" "role" "level"
"2" "manager" "3"
"3" "manager" "2"
"1" "programmer" "6"
范式设计的优缺点
优点:
1.拆分的更细,冗余数据更少
2.占用空间更小,可以更好的放入内存,操作更快
缺点:
会导致查询需要频繁使用多表关联,会导致执行效率降低、并且有些索引无法很好执行。
反范式设计的优缺点
优点:
把所有业务相关的字段尽可能的放入一张表中,避免多表关联查询。
单表可以更好的使用索引,有时候执行效率更高!
缺点:
更多的冗余数据,导致更新或者删除缓慢。
反范式常用的冗余设计
1. 基于静态数据的冗余
静态数据指相关字段变更频率不高,如用户资料,可作冗余字段
以消息表为例
Fuid,Tuid,Msg,Dateline
范式化设计后,在内容呈现上可能需要涉及多表关联,因为用户想知道发消息的人是谁?
那么,可增加冗余字段:Funame
2. 基于谓词的冗余
有些where连接条件很热门,一个谓词为多个SQL服务,那么,我们可以把这些热门的谓词收集,集中存在到一张冗余表
以用户登录为例子,假设有上亿条用户资料并做了分表处理,用户只关心uname,根据uname需要到各个分表去查询uid,此时,我们可按:uname,uid建立冗余表
3. 基于聚会函数的冗余
频繁的count,max,sum等需求,例如,论坛今日发帖总量,可建立冗余字段Spost
4. 基于排序的冗余
索引用来加速查询或者已经是件家喻户晓的事,但还有一个优势,即:降低排序成本。
仍然以消息表为例,若我们按uname对消息做排序的代价估计会蛮高的,但如果在消息表里把uname冗余并且建立好索引,则可以借助索引来抵消排序