10. 详细说明:所有动态长度字符串全部使用 VARCHAR 类型,类似于状态,有限类别的字段, 也使用可以比较明显表示出实际意义的字符串,而不应该使用INT之类的数字来代替;2. 固定长度的字符串使用 CHAR 类型,所有单个字符的全部使用 CHAR 类型,而不应该使用VARCHAR 类型;3. 仅仅当字符数量可能超过 20000 个的时候,可以使用 TEXT 类型来存放字符类数据。所有使用 TEXT 类型的字段必须和原表进行分拆,与原表主键单独组 成另外一个表进行存放;4. 需要精确到时间(年月日时分秒)的字段可以使用DATETIME 或TIMESTAMP,但请注意各自能表达的范围,以及是否需要用到TIMESTAMP的特性;5. 所有只需要精确到天的字段全部使用 DATE 类型,而不应该使用 TIMESTAMP或者DATETIME 类型;6. 自增序列类型的字段只能使用 INT 或者 BIGINT,且明确标识出为无符号型 (UNSIGNED),除非确实会出现负数,仅当该字段数字取值会超过42亿,才使 用 BIGINT 类型;
11. 2.2 绑定变量和替代变量使用规范基本原则: 所有 Query 的 Where 条件中的变量,都需要使用绑定变量来实现,此要求并不完全是基于性能的考虑,更多是基于安全方面的考虑,如若有任何不使用绑定变量的需求,都必须通过安全部门的审核并征得同意。详细说明:. 在 iBatis 的 SqlMap 文件中绑定变量使用 “#var_name#”表示,替代变量使用$var_name$”;所有需要动态 Order By 条件的 Query,在使用替代变量过程中,需要将可能传入的内容以枚举类写死在代码中,禁止接受任何外部传入内容;. 对于不变的常量条件,请使用常量而不是变量;. IN子句,使用"Iterate + 数组类型变量"的方式实现绑定变量而不是通过代码拼接 Query 语句,例如:<isNotEmpty prepend="and" property="userIds"><iterate property="userIds" open="t.user_id in (" close=")" conjunction=",">#userIds[]#</iterate></isNotEmpty>iBatis会生成t.user_id in (1,2,3,4,5 ...)的语句
12. 2.3 数据类型转换规范基本原则: 在所有 Query 的 Where 条件中必须使用和过滤字段完全一致的数据类型,杜绝任何隐式类型转换,避免造成因为数据类型不匹配而导致 Query 执行计划的出错,造成性能问题.详细说明:1> 所有 Where 条件的字段上不允许使用函数做类型转换,如有需要转换类型,只能转换过滤值,而不是转换字段.2> 最为常见的隐式类型转换常见于时间类型与字符串类型之间,建议所有时间类型字段在iBatis中均以时间类型传入,或者以字符串传入然后通过时间函数转换字符串为合法的时间格式 ,如下:SELECT * FROM member WHERE gmt_create=DATE_FORMATE('2009010101:02:03','%Y-%m-%d %H:%i:%s');3> 在表连接 Query 中,如果连接条件两端的数据类型不一致,必须保证将驱动表的连接条件数据类型转换为与被驱动表一致的数据类型.
14. 2.5 字段上添加函数使用规范基本原则: 禁止在 WHERE 条件中出现的过滤字段上,使用任何函数进行类型或格式的转换;正确的做法是把传入比较的值转换为列类型所需要的。错误的写法:SELECT username FROM gl_user WHERE DATE_FORMAT(gmt_create, '%Y%m%d%H%i%s')='20090501022300‘;正确的写法:SELECT username FROM gl_user WHERE gmt_create=DATE_FORMAT('20090501022300', '%Y-%m-%d %H:%i:s');
15. 2.6 表连接规范基本原则:所有非外连接SQL(即INNER JOIN),请把关联表统一写到 FROM字句中,关联条件与过滤条件统一写到WHERE字句中.出于代码的可读性原因,所有外连接SQL语句中,请一律使用LEFT JOIN,禁用RIGHT JOIN。另外,请注意LEFT JOIN字句中,右边位置表的条件书写位置不同的影响: SELECT A.rolename,A.gmt_create,B.nickname FROM gl_role A LEFT JOIN gl_roledetail B ON A.ID=B.roleidAND B.roleID=2;+-------------+---------------------+----------+| rolename | gmt_create | nickname |+-------------+---------------------+----------+| 163.com | 0000-00-00 00:00:00 | test2 | | sina.com | 0000-00-00 00:00:00 | NULL | | hotmail.com | 0000-00-00 00:00:00 | NULL | | 126.com | 2009-08-20 18:20:18 | NULL | +-------------+---------------------+----------+SELECT A.rolename,A.gmt_create,B.nickname FROM gl_role A LEFT JOIN gl_roledetail B ON A.ID=B.roleidWHERE B.roleID=2;+----------+---------------------+----------+| rolename | gmt_create | nickname |+----------+---------------------+----------+| 163.com | 0000-00-00 00:00:00 | test2 | +----------+---------------------+----------+
16. 2.7 分页查询规范基本原则: 分页查询语句全部都需要带有排序条件,除非商业方明确要求不要使用任何排序来随机展示数据。详细说明:1> 常规分页语句写法(start:起始记录数,page_offset:每页记录数):SELECT ID,username FROM gl_user WHERE username like '%@163.com' ORDER BY M.gmt_create LIMIT start, page_offset;2> 多表 Join 的分页语句,如果过滤条件在单个表上,需要先分页,再 Join:低性能写法:SELECT M.username,P.rolename FROM gl_user M INNER JOIN gl_role P ON M.ID=P.userid WHERE username like '%@163.com' ORDER BY M.gmt_create LIMIT start, page_offset;高性能写法:SELECT M.username,P.rolenameFROM (SELECT ID,username FROM gl_user WHERE username like '%@163.com' ORDER BY M.gmt_create LIMIT start, page_offset)M,gl_role PWHERE M.ID=P.userid;这样写的前提是关联的表之间记录一一对应,否则可能会返回的记录数目少于或多于page_offset的值。
21. 7.MySQL使用建议1>. 进行数据库结构设计的时候,考虑适当的冗余,尽量确保应用读写数据的SQL简洁.2>. 所有字符集为utf8,校对规则为utf8_general_ci ,默认是不区分英文字母大小写,若有需求区分大小写,请跟DBA特别声明,或者表定义语句指定 COLLATE ‘utf8_bin’.3>.尽量不需要使用子查询,特别是IN的方式,可考虑转化为EXISTS. SELECT * FROM A WHRE A.ColName1 IN (SELECT DISTINCT ID FROM B WHERE ..);建议改写为: SELECT * FROM A WHRE EXISTS (SELECT 1 FROM B WHERE B.ID= A.ColName1...);4> 要返回MySQL自增序列的ID值,可以考虑使用函数LAST_INSERT_ID(),此函数只能返回同 一个SESSION最近一次对有AUTO_INCREMENT属性表INSERT的ID值.5> 所有的时间字段值,请以MySQL数据库的时钟为准,除用户输入的时间值外.6> 对于项目的数据量、PV等合理评估,我们DBATEAM相关人员,会给大家推荐合理成熟的数据存取架构,增强系统的扩展性与用户体验,以及高可用性等.