Data: 2017-12-01 13:28:24Form: JournalClick: 8
数据库命名:数据库名的命名一般和项目的名称保持一致,不要随意的起名字。
数据库编码: 尽量采用utf8mb4而不使用utf8。MySQL 的“utf8”实际上不是真正的UTF-8,真正的UTF-8是每个字符最多四个字节,而MySQL的“utf8”只支持每个字符最多三个字节。MySQL一直没有修复这个 bug,他们在 2010 年发布了一个叫作“utf8mb4”的字符集,绕过了这个问题。MySQL的“utf8mb4”才是真正的“UTF-8”。所有在使用“utf8”的 MySQL和MariaDB用户都应该改用“utf8mb4”,永远都不要再使用“utf8”。第三方像微信和QQ的昵称一般包含一些表情符号等,这些符号是属于UTF-8的,但是如果数据库中使用utf-8将不能保存这些特殊字符,只能将数据库和表的编码改为utf8mb4才能保存第三方的昵称。utf8转utf8mb4具体操作方法参考文章 https://mathiasbynens.be/notes/mysql-utf8mb4#utf8-to-utf8mb4
数据库表结构的设计是最基础也是最重要的,因为一旦数据库表设计完毕并投入使用,将来再进行修改就相对比较麻烦,特别数据量大时增加字段修改字段类型都比较麻烦,因此在进行数据库设计的时候一定要尽可能的考虑周到。
数据库表设计要遵守如下原则:
表的命名一般遵守 “业务名称 _ 表名“或者是“项目名_ 表名“的格式,对于业务名称一般都是简写,不全拼,全拼表名会太长,如sys_user(系统模块对应的用户表),对于一些公用的可以使用tbl(table简写)作为模块名,如字典表 tbl_dictionary。
表名不使用复数形式,表名应该仅仅表示表里面的实体内容,不应该表示实体数量。如sys_user不要命名为sys_users。
为什么要使用前缀?如果多个项目都使用同一个数据库的话,可以防止命名冲突,例如用户表,如果没有设置前缀,估计大家都会命名为user,其它项目要使用这个名字就冲突了,为了解决这种问题,可以在表名上增加一个前缀,前缀为项目名称,如xxx_user, yyy_user这样就解决了这种命名冲突问题。在公司中可以经常看到有时候数据库中的所有表都用项目的简称做前缀,很可能所有表只有这一种前缀,也没有分多个前缀。 不同项目一般都会创建自己的数据库,但是不能保证万一会使用同一个数据库的情况,如两个项目关联很大可能会使用同一个数据库或者因为其它原因,这样使用前缀就能解决将来可能带来的命名冲突的问题。什么情况下命名会冲突?最常见的一种情况是你使用了第三方框架,而第三方框架需要使用数据库记录一些数据,而这些框架中用到的表名很可能与你业务中的表名会冲突,这个时候你要么不使用这个框架,要么将自己业务的表进行重命名,总之我们还是为表设置前缀,因为将来是不确定的,增加系统的可扩展性是没有坏处的。下面看一下Spring Batch框架中就用到数据库了,该框架的表结构都是以BATCH作为第一个前缀,第二个前缀是业务模块名,后面的才是真正的表名,通过“项目前缀_业务前缀_表名”这种命名法扩展性是最好的,只不过表名会变的很长。
在比较复杂的系统中,通过表名前缀可以大概了解到表所在的模块,相同的业务表是在一起的,这样做日常开发和看的时候会比较方便,新人了解系统数据结构的时候也有章可循。
不同的数据类型搜索的方式不同,所以说要选择合适的数据类型。用尽量少的存储空间来存数一个字段的数据, 缩小存储空间换取查询时间,能用int的就不用char或者varchar,能用tinyint的就不用int,使用UNSIGNED存储非负数值,其中无符号值可以避免误存负数,且扩大了表示范围。合适的字符存储长度,不但节约数据库表的存储空间、节约索引存储,更重要的是提升检索速度。 尽量使用数字型字段,提高数据比对效率。
创建表时我们经常看到长度这一列,例如 tinyint(2),对于整型来说小括号中的2不是指的存储长度,而是指的零填充,对于字符串指的是长度,zerofill零填充,当数据的长度小于指定的长度时,会使用0来填充缺失的长度。零填充在mysql客户度中看不出来,使用命令行可以看出来。
如果tinyint(2)中的2代表长度,那么102就插入不成功,事实上是插入成功的。
使用命令行可以看到1和2因不到两位长度,差一位,需要用0来填充
根据实际需要选择能够满足应用的最小存储日期类型。
timestamp与datetime
两者都可用来表示YYYY-MM-DD HH:MM:SS[.fraction]类型的日期。
都可以使用自动更新CURRENT_TIMESTAMP
对于TIMESTAMP,它把客户端插入的时间从当前时区转化为UTC(世界标准时间)进行存储。查询时,将其又转化为客户端当前时区进行返回。而对于DATETIME,不做任何改变,基本上是原样输入和输出。
timestamp占用4个字节:timestamp所能存储的时间范围为:‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’
datetime占用8个字节 :datetime所能存储的时间范围为:‘1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’
总结:TIMESTAMP和DATETIME除了存储范围和存储方式不一样,没有太大区别。如果需要使用到时区就必须使用timestamp,如果不使用时区就使用datetime因为datetime存储的时间范围更大
注意:
使用PROCEDURE analyse() 来查看列的具体指标来帮助优化列。
SELECT * FROM tbl_user PROCEDURE analyse();
MySQL字段属性应该尽量设置为NOT NULL,除非你有一个很特别的原因去使用 NULL 值,你应该总是让你的字段保持 NOT NULL,对于没有值的指定一个默认值,如之前使用null的varchar可以默认为空字符串“”,之前是数字类型的可以用0做为默认值 。
在MySQL中NULL其实是占用空间的,“可空列需要更多的存储空间”:需要一个额外字节作为判断是否为NULL的标志位“需要mysql内部进行特殊处理”, 而空值""是不占用空间的。
含有空值的列很难进行查询优化,而且对表索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替null。
联表查询的时候,例如SELECT user.username, info.introduction FROM tbl_user user LEFT JOIN tbl_userinfo info ON user.id = info.user_id; 如果tbl_userinfo.introduction设置的可以为null, 假如这条sql查询出了对应的记录,但是username有值,introduction没有值,那么就不是很清楚这个introduction是没有关联到对应的记录,还是关联上了而这个值为null,null意思表示不明确,有歧义
注意:NULL在数据库里是非常特殊的,任何数跟NULL进行运算都是NULL, 判断值是否等于NULL,不能简单用=,而要用IS NULL关键字。使用 ISNULL()来判断是否为 NULL 值,NULL 与任何值的直接比较都为 NULL。
常用的存储引擎的选择有MYISAM、InnoDB、MEMORY,不同的存储引擎支持的功能不一样,MySQL5.5之后默认的是InnoDB。绝大部分场景都是使用InnoDB引擎。
表引擎取决于实际应用场景;日志及报表类这种只涉及到插入和查询并且查询操作更多的建议用myisam;对事务要求高的使用innodb引擎。
建议:不要混合使用存储引擎,实际场景中会有MyISAM和InnoDB混合使用的情况,但是这样有问题,比如一个事务同时操作了myisam引擎的表和innodb引擎的表,而myisam是不支持事务的,就会造成myisam表没有回滚。现在开发中绝大部分都是使用InnoDB,也不经常见到myisam,至少我工作中没见到过。
mysql5.0之后默认为InnoDB创建表的时候可以指定engine,也可以通过alter table语句来修改存储引擎。
create table tbl_user (
...
)
Copyright © 2016 by 郭俊杰(Journal)