mysqldecimal⽐较⼤⼩_详细解读阿⾥⼿册之MySQL
阿⾥⼿册是阿⾥⼯程师多年⼀线经验的结晶,遵循其中的约定与规范,能很⼤程度的减少某些未知的隐患。
其规约强度由强到弱分为强制、推荐、参考三⼤类。
本⽂详细解读了阿⾥⼿册的MySQL部分,如果是⼀些很明确的、不需要过多解释的约定,本⽂不会解读。
本⽂分为四部分: 建表规约 索引规约 SQL语句 ORM映射
1 建表规约腋下副乳怎么消除
【强制】表达是与否概念的字段,必须使⽤ is_xxx 的⽅式命名,数据类型是 unsigned tinyint (1 表⽰是,0 表⽰否)。 说明:任何字段如果为⾮负数,必须是 unsigned。 注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀,所以,需要在设置 从 is_xxx 到 Xxx 的映射关系。数据库表⽰是与否的值,使⽤ tinyint 类型,坚持 is_xxx 的 命名⽅式是为了明确其取值含义与取值范围。 正例:表达逻辑删除的字段名 is_deleted,1 表⽰删除,0 表⽰未删除。 解读:从优化⾓度来讲,应该按字段的⽤途来定义合适的类型。表达是与否,⽤长度为1个字节的tinyint⾜以。
【强制】表名、字段名必须使⽤⼩写字母或数字,禁⽌出现数字开头,禁⽌两个下划线中间只 出现数字。数据库字段名的修改代价很⼤,因为⽆法进⾏预发布,所以字段名称需要慎重考虑。 说明:MySQL 在 Windows 下不区分⼤⼩写,但在 Linux 下默认是区分⼤⼩写。因此,数据库名、 表名、字段名,都不允许出现任何⼤写字母,避免节外⽣枝。 正例:
aliyun_admin,rdc_config,level3_name 反例:AliyunAdmin,rdcConfig,level_3_name * 解读:Win环境下开发,代码中⽤的表名是⼩写,本地数据库⽤的是⼤写,那么在win环境下没有问题,但发布到linux环境会有问题。Linux下MySQL安装完后默认:区分表名的⼤⼩写,不区分列名的⼤⼩写
MySQL在Linux下数据库名、表名、列名、别名⼤⼩写规则:
(1)数据库名与表名是严格区分⼤⼩写
(2)表的别名是严格区分⼤⼩写
(3)列名与列的别名在所有的情况下均是忽略⼤⼩写的
(4)变量名也是严格区分⼤⼩写的
【强制】表名不使⽤复数名词。 * 说明:表名应该仅仅表⽰表⾥⾯的实体内容,不应该表⽰实体数量,对应于 DO 类名也是单数 形式,符合表达习惯。
【强制】禁⽤保留字,如 desc、range、match、delayed 等,请参考 MySQL 官⽅保留字。
【强制】主键索引名为 pk_字段名;唯⼀索引名为 uk_字段名;普通索引名则为 idx_字段名。 * 说明:pk_ 即 primary key;uk_ 即unique key;idx_ 即 index 的简称。
【强制】⼩数类型为 decimal,禁⽌使⽤ float 和 double。 说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的⽐较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和⼩数分开存储。 解读:float和double都是浮点型,⽽decimal是定点型。MySQL 浮点型和定点型可以⽤类型名称后加(M,D)来表⽰,M表⽰该值的总共长度,D表⽰⼩数点后⾯的长度。
FLOAT和DOUBLE在不指定精度时,默认会按照实际的精度来显⽰,⽽DECIMAL在不指定精度时,默认整数为10,⼩数为0。所以建议在定义表时,定义(M,D)。
float和double在设置超过定义长度的数值时,会⾃动四舍五⼊,decimal会截断,并给出⼀条警告。
精度损失问题:float和double类型的列,在做sum计算时,会丢失精度,⽽decimal会精确计算。
【强制】如果存储的字符串长度⼏乎相等,使⽤ char 定长字符串类型。 * 解读:从优化⾓度来说,如果⼀个表的所有字段都是定长的,那么每⼀条数据也就是定长的,数据库就可以直接计算出下⼀条数
据的偏移量,查询速度会更快。
【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度⼤于此值,定义字段类型为 text,独⽴出来⼀张表,⽤主键来对应,避免影响其它字段索 引效率。 * 解读:MySQL5.0以上版本,varchar最⼤可以存储65535字节数据(内容开头⽤1-2个字节存储长度信息,超过255时⽤两个字节,所以最⼤65535)。
我们通常编码设置为U8,每个字符最多占3个字节,那么最⼤长度不能超过21845。
若定义的时候超过上述限制,则varchar字段会被强⾏转为text类型,并产⽣warning。
此外,受MYSQL⾏长度限制影响,MySQL要求⼀个⾏的定义长度不能超过65535。若定义的表长度超过这个值,则提⽰ERROR 1118 (42000): Row size too large。
数据库中定义的varchar(20)指的是20个字符。
关于5000的建议:由于通常定义的U8每个字符占3个字节,那么5000字符需要15000个字节,考虑⾏最⼤长度限制和别的列,以及查询性能,推荐5000。
【强制】表必备三字段:id, gmt_create, gmt_modified。 * 说明:其中id必为主键,类型为bigint unsign
ed、单表时⾃增、步长为1。gmt_create, gmt_modified 的类型均为 datetime 类型,前者现在时表⽰主动创建,后者过去分词表⽰被动更新。
【推荐】表的命名最好是加上“业务名称_表的作⽤”。 * 正例: alipay_task / force_project / trade_config
【推荐】库名与应⽤名称尽量⼀致。
【推荐】如果修改字段含义或对字段表⽰的状态追加时,需要及时更新字段注释。
【推荐】字段允许适当冗余,以提⾼查询性能,但必须考虑数据⼀致。冗余字段应遵循:
1) 不是频繁修改的字段。
2) 不是 varchar 超长字段,更不能是 text 字段。
正例: 商品类⽬名称使⽤频率⾼,字段长度短,名称基本⼀成不变,可在相关联的表中冗余存储类⽬名称,避免关联查询。
【推荐】单表⾏数超过 500 万⾏或者单表容量超过 2GB,才推荐进⾏分库分表。
说明: 如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
文明用语解读:超过后对各⽅⾯性能影响较⼤,淘新闻出现过⼀次表过⼤引发的故障。
【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。便携式投影仪
正例: 如下表,其中⽆符号值可以避免误存负数, 且扩⼤了表⽰范围
|类型|年龄|字段类型|字段长度|取值范围| |----|---|----|----|-----| |⼈|150岁之内|tinyint unsigned|1|⽆符号值: 0~255|
2 索引规约
【强制】业务上具有唯⼀特性的字段,即使是多个字段的组合,也必须建成唯⼀索引。 说明: 不要以为唯⼀索引影响了 inrt 速度,这个速度损耗可以忽略,但提⾼查找速度是明显的; 另外,即使在应⽤层做了⾮常完善的校验控制,只要没有唯⼀索引,根据墨菲定律,必然有脏数据产⽣。 解读:墨菲定律:如果事情有变坏的可能,不管这种可能性有多⼩,它总会发⽣。
【强制】超过三个表禁⽌ join。需要 join 的字段,数据类型必须绝对⼀致; 多表关联查询时,保证被关联的字段需要有索引。 * 说明: 即使双表 join 也要注意表索引、 SQL 性能。
【强制】在 varchar 字段上建⽴索引时,必须指定索引长度,没必要对全字段建⽴索引,根据实际⽂本区分度决定索引长度即可。 说明: 索引的长度与区分度是⼀对⽭盾体,⼀般对字符串类型数据,长度为 20 的索引,区分度会⾼达 90%以上,可以使⽤
count(distinct left(列名, 索引长度))/count()的区分度来确定。 * 解读:区分度是指不重复的索引值和数据表的记录总数的⽐值,范围(0,1],值越⾼则查询效率越⾼。
对于blob,text,varchar的列必须使⽤前缀索引,MySQL不允许索引这些列的完整长度。
最好选择⾜够长的前缀保证较⾼的区分度,也不能太长(节省空间)。
【强制】页⾯搜索严禁左模糊或者全模糊,如果需要请⾛搜索引擎来解决。
说明: 索引⽂件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么⽆法使⽤此索引。
【推荐】如果有 order by 的场景,请注意利⽤索引的有序性。 order by 最后的字段是组合索引的⼀部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。
lect t1.* from ur_game_info t1, (lect id from ur_game_info limit 900000, 20) t2 where t1.id = t2.id; // 优化后耗时
因隐式转换,未命中索引
隐式转换规则: 两个参数⾄少有⼀个是 NULL 时,⽐较的结果也是 NULL,例外是使⽤ <=> 对两个 NULL 做⽐较时会返回 1,这两种情
长宁公租房
【强制】 在代码中写分页查询逻辑时,若 count 为 0 应直接返回,避免执⾏后⾯的分页语句。 * 解读:先查询COUNT,后查询分页数据
【强制】不得使⽤外键与级联,⼀切外键概念必须在应⽤层解决。 * 说明:以学⽣和成绩的关系为例,学⽣表中的 student_id是主键,那么成绩表中的 student_id则为外键。如果更新学⽣表中的 student_id,同时触发成绩表中的 student_id 更新, 即为级联更新。外键与级联更新适⽤于单机低并发,不适合分布式、⾼并发集群; 级联更新是强阻塞,存在数据库更新风暴的风险; 外键影响数据库的插⼊速度。
【强制】禁⽌使⽤存储过程,存储过程难以调试和扩展,更没有移植性。
【强制】数据订正(特别是删除、 修改记录操作) 时,要先 lect,避免出现误删除,确认⽆误才能执⾏更新语句。 * 解读:⼿动执⾏SQL来修改或删除数据时,先⽤where后的条件lect⼀遍,确认数据⽆误后,在执⾏update或delete。
消防绘画图片
【推荐】 in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内。
【参考】 如果有国际化需要,所有的字符存储与表⽰,均以 utf-8 编码,注意字符统计函数的区别。 说明:SELECT LENGTH(“轻松⼯作”); 返回为 12,统计字节数SELECT CHARACTER_LENGTH(“轻松⼯作”); 返回为 4,统计字符数如果需要存储表情,那么选择 utf8mb4 来进⾏存储,注意它与 utf-8 编码的区别。 解读:utf8可以存储3个字节的数据,utf8mb4可以存储四个字节,专门⽤来兼容4个字节的unicode,utf8mb4是utf8的超集,将编码从utf8改为utf8mb4⽆需额外转换。
Emoji表情不在utf8的3个字节的表⽰范围之内,可以⽤utf8mb4存储。
【参考】 TRUNCATE TABLE ⽐ DELETE 速度快,且使⽤的系统和事务⽇志资源少,但 TRUNCATE⽆事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使⽤此语句。说明: TRUNCATE TABLE 在功能上与不带 WHERE ⼦句的 DELETE 语句相同。
4 ORM映射
日常生活用品【强制】在表查询中,⼀律不要使⽤ * 作为查询的字段列表,需要哪些字段必须明确写明。 * 说明:
跳棋最快21走法图解
1) 增加查询分析器解析成本。
2) 增减字段容易与 resultMap 配置不⼀致。
3)⽆⽤字段增加⽹络消耗,尤其是 text 类型的字段。
解读:可以更好的利⽤“覆盖索引”。
【强制】 POJO 类的布尔属性不能加 is,⽽数据库字段必须加 is_,要求在 resultMap 中进⾏字段与属性之间的映射。 * 说明: 参见定义 POJO 类以及数据库字段定义规定,在中增加映射,是必须的。在 MyBatis Generator ⽣成的代码中,需要进⾏对应的修改。
【强制】不要⽤ resultClass 当返回参数,即使所有类属性名与数据库字段⼀⼀对应,也需要定义; 反过来,每⼀个表也必然有⼀个POJO 类与之对应。 * 说明: 配置映射关系,使字段与 DO 类解耦,⽅便维护。胜利号风帆战列舰
【强制】l 配置参数使⽤: #{}, #param# 不要使⽤${} 此种⽅式容易出现 SQL 注⼊。 * 解读:#与$的区别:在预编译中的处理是不⼀样的。#{} 在预处理时,会把参数部分⽤⼀个占位符 ? 代替,如:
lect * from ur where name = ?;
⽽ ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成
lect * from ur where name = 'zhangsan’;
以上,#{} 的参数替换是发⽣在 DBMS 中,⽽ ${} 则发⽣在动态解析过程中。