mysql数据库设计开发规范

1.设计

  1. 一般都使用INNODB存储引擎,除非读写比率<1%,才考虑使用MYISAM存储引擎;其他存储引擎请在DBA的建议下使用。

  2. Stored procedure (包括存储过程,函数,触发器)对于MYSQL来说还不是很成熟,没有完善的出错记录处理,不建议使用。

  3. UUID(),USER()这样的MYSQL INSIDE函数对于复制来说是很危险的,会导致主备数据.不一致。所以请不要使用。如果一定要使用UUID作为主键,让应用程序来产生。

  4. 请不要使用外键约束,如果数据存在外键关系,请在程序层面实现。

  5. 如果应用使用的是长连接,应用必须具有自动重连的机制。但请避免每执行一个SQL去检查一次DB可用性。

  6. 如果应用使用的是长连接,应用应该具有连接的TIMEOUT检查机制,及时回收长时间没有使用的连接。TIMEOUT时间一般建议为20min。

  7. 我们所有的MySQL数据库除历史原因外,都必须采用UTF8编码。

  8. Mysql 对DDL支持很差,表结构推荐设计为Key-Value结构。如果是关系型结构的数据库,请尽量预留一些字段,如value1 ,value2 ,value3。

2.命名

  a) 命名应使用富有意义的英文词汇,多个单词组成的,中间以下划线分割。

  b) 命名只能使用英文字母,数字和下划线。

  c) 命名避免使用Mysql的保留字(详见附录A)和系统关键字。

  d) 命名长度以不超过15个字符为宜(避免超过20)。

  e) 命名全部采用小写,并且名称前后不能加引号。

? 数据库对象设计规范

1. 表

设计

  a) 在设计时尽量包含两个日期字段:gmt_created(创建日期),gmt_modified(修改日期)且非空, 对表的记录进行更新的时候,必须包含对gmt_modified字段的更新。

  b) 必须要有主键,主键尽量用自增字段类型,推荐类型为INT或者BIGINT类型。

  c) 需要多表join的字段,数据类型保持绝对一致。

  d) Mysql的表尽量设置成KV(Key-Value)结构,这样便于扩展和维护。

  e) 当表的字段数非常多时,可以将表分成两张表,一张作为条件查询表,一张作为详细内容表(主要是为了性能考虑)。

  f) 当字段的类型为枚举型或布尔型时,建议使用char(1)类型。

  g) 同一表中,所有varchar字段的长度加起来,不能大于65535.如果有这样的需求,请使用TEXT/LONGTEXT类型。

  h) 由于MYSQL表DDL维护成本很高,所以在适当的时候,可以有一定的字段容余。比如:Value1,Value2,Value3这样的字段。

   i) 每张表定义的ID字段,如果涉及数据量比较大,请尽量使用BigInt(补充)

   j) 对于日期类型Datetime和Timestamp的使用,GMT_Created和GMT_Modified建议明确类型(补充)

命名

  a) 同一个模块的表尽可能使用相同的前缀,表名尽可能表达含义,例如: CRM_SAL_FUND_ITEM。

  b) 字段命名应尽可能使用表达实际含义的英文单词或缩写,如,公司ID,不要使用:corporation_id, 而用:corp_id 即可。

  c) 布尔值类型的字段命名为is+描述。如member表上表示是否为enabled的会员的字段命名为IsEnabled。

常用字段类型

  
TINYINT  1个字节, -128 to 127 || 0 to 255 
SMALLINT  2个字节, -32768 to 32767 || 0 to 65535 
MEDIUMINT  3个字节, -8388608 to 8388607 || 0 to 16777215. 
INT, INTEGER  4个字节, -2147483648 to 2147483647 || 0 to 4294967295. 
BIGINT  8个字节, -9223372036854775808 to 922337203685477580 0 to 18446744073709551615 
DECIMAL(P,S)  定点数(以字符串形式存放) 默认:P为10,S为0,最大65位 
DATE  范围‘1000-01-01‘到‘9999-12-31‘ 格式‘YYYY-MM-DD‘ (3字节) 
Time  范围‘-838:59:59‘到‘838:59:59‘ 格式‘HH:MM:SS‘ (3字节) 
DATETIME  范围 ‘1000-01-01 00:00:00‘ 到‘9999-12-31 23:59:59‘ 格式 ‘YYYY-MM-DD HH:MM:SS‘ (8字节) 
TIMESTAMP  范围 ‘1970-01-01 00:00:00‘ 到2037年格式‘YYYY-MM-DD HH:MM:SS‘ 宽度固定为19个字符(4字节) 不建议使用 
VARCHAR(n)  变长字符串,65532>n>4, 注意,n是字符数,而不是字节数 
CHAR(n)  定长字符串,n范围(0,255), 如果不是定长的数据,n<=4 时才使用 
TINYBLOB, TINYTEXT  存储L+1个字节,其中L < 2^8 
BLOB, TEXT  存储 L+2个字节,其中L < 2^16 
MEDIUMBLOB, MEDIUMTEXT  存储 L+3个字节,其中L < 2^24 
LONGBLOB, LONGTEXT  存储L+4个字节,其中L < 2^32 
   

字段注释

a) 标准字段注释由一组"@"开头的标签+空格+文本组成。

以MD_USER表的部分字段为例:

NameType Comments 
PARTY_ID  VARCHAR(20) @desc 主键ID 
CORP_ID  VARCHAR(20) @desc 用户所在公司ID @fk md_corp_id 
STATUS  VARCHAR(20) @desc 状态@values disable|enable:未激活状态|激活状态 
IS_PRI_ACCOUNT CHAR(1)  @desc 是否为主账号。后台生成UK时使用@values y|n:是帐号,非主帐号@logic 一个公司内部,有且仅有一个主账号存在
     

b) 注释标签说明

标签名 中文含义 必填 备注 
@desc  字段中文描述  Yes   
@fk  字段对应的外键字段     
@values  取值范围说明。多个值以"|"分隔  如此字段的值由系统自动生成,可忽略不书写。   
@sample  数据范本  对于复杂数据格式,最好给一个数据范本。   
@formula  计算公式  写明该字段由哪些字段以何种公式计算得到。   
@logic  数据逻辑  简要写明该字段的数据是在何种业务规则下,如何变化的。   
@redu  标识此字段冗余     
@depr  标识此字段已废弃  简要写明:废弃人 废弃日期 废弃原因   
       

2. 索引

设计

  a) Bitmap索引通常不适合我们的环境。

  b) 索引根据实际SQL,由DBA创建。

  c) 不要创建带约束的索引,所有的约束效果都通过显示创建约束然后再using index一个已经创建好的普通索引来实现。

命名

  a) <table_name><column_name>_ind,各部分以下划线()分割。

  b) 多单词组成的column name,取前几个单词首字母,加末单词组成column_name。如:sample表member_id上的索引:sample_mid_ind。

3. 约束

  设计
    a) 主键最好是无意义的,,统一由Auto-Increment字段生成整型数据,不建议使用组合主键。

    b) 若要达到唯一性限制的效果,不要创建unique index,必须显式创建普通索引和约束(pk或uk),即先创建一个以约束名命名的普通索引,然后创建一个约束,用using index ...指定索引。

    c) 当删除约束的时候,为了确保不影响到index,最好加上keep index参数。

    d) 主键的内容不能被修改。

    e) 外键约束一般不在数据库上创建,只表达一个逻辑的概念,由程序控制。

    f) 当万不得已必须使用外健的话,必须在外健列创建INDEX。

  命名

    a) 主键约束: _pk结尾,<table_name>_pk;

    b) unique约束:uk结尾,<table_name><column_name>_uk;

    c) check约束: _ck 结尾,<table_name>_<column_name>_ck;

    d) 外键约束: _fk 结尾,以pri连接本表与主表,<table_name>pri<table_name>_fk;

4. 触发器

  命名
    a) <table_name>_A(After)B(Before)I(Insert)U(Update)D(Delete)_trg。

    b) 若是用于同步的触发器以sync作为前缀:sync_<table_name>_trg。

5. 过程、函数

  设计
    a) 如果要在MYSQL里使用存储过程类的技术,请务必和DBA沟通确认。

  命名

    a) 过程以proc_开头,函数以func_开头。

    b) 变量命名约定:本地变量以v_为前缀,参数以p_为前缀,可以带_I(输入),_O(输出)、_IO(输入输出)表示参数的输入输出类型。

? SQL开发规范

一.编码规范

  1. 使用SQL操作数据库前,必须由use DB_name 开始

  Use Test ;

  Insert into Table_name values ( … ) ;

  Commit;

  2. 如果需要事务的支持,在确认使用了innodb 存储引擎的前提下,在数据库连接时,先关闭自动提交

  比如,设定set auto_commit =0 ;

  3. 写到应用程序里的SQL语句,禁止一切DDL操作

  例: Create table , Drop table , Create database , Drop database , Alter table ,grant …… 如有特殊需要,必需与DBA协商同意方可使用。

  4. 获取当前时间请使用now(),不要用sysdate()来代替

  这对复制来说是很危险的,会导致主从数据不一致的情况; 因为sysdate,取的是系统主机时间,在BINLOG会原文传输, 当在应用时会与主库产生差异。

  5. 写SQL的时候一定要给每个字段指定表名做前缀

  比如: select a.id,a.name from test a; 好处是 一来带来性能的提升, 二来可以避免一些错误的发生。

  6. 在 iBatis 的 SqlMap 文件中绑定变量使用 “#var_name#”表示,替代变量使用“$var_name$”

  所有需要动态Order By 条件的Query,在使用替代变量过程中,需要将可能传入的内容以枚举类写死在代码中,禁止接受任何外部传入内容。

  7. 请不要写select * 这样的代码,指定需要的字段名

  8. Mysql 对日期(datetime)允许“不严格”语法

  任何标点符都可以用做日期部分或时间部分之间的间割符。例如, ‘98-12-31 11:30:45‘、‘98.12.31 11+30+45‘、‘98/12/31 11*30*45‘和‘98 (12)31 11^30^45‘是等价的。] 我们自己约定一种写法,与Oracle相通: ‘2009-12-31 11:30:45‘

  9. Mysql 的日期与字符是相同的,所以不需要做另外的转换

  例:Select e.username from employee e where e.birthday >=’1998-12-31 11:30:45’

  10. 避免多余的排序。使用GROUP BY 时,默认会进行排序,当你不需要排序时,可以使用order by null

  Select product,count(*) cnt from crm_sale_detail group by product order by null;

  11. 避免在where子句中对字段施加函数

     a) 通常,不允许在字段上添加函数或者表达式,这样将导致索引失效,如:

       错误的写法: select * from iw_account_log where substr(username,1,5)=’abcde’

       正确的写法: select * from iw_account_log where username like ’abcde%’

     b) 如果是业务要求的除外,但需要在编写时咨询DBA

     c) 特别注意,当表连接时,用于连接的两个表的字段如果数据类型不一致,则必须在一边加上类型转换的函数

  12. 严格要求使用正确类型的变量,杜绝Mysql做隐式类型转换的情况

  13. 全模糊查询无法使用INDEX,应当尽可能避免

      比如:select * from table where name like ‘%jacky%‘;

  14. 表连接规范

     a) 所有非外连接SQL(即INNER JOIN),请把关联表统一写到FROM字句中,关联条件与过滤条件统一写到WHERE字句中

     b) 出于代码的可读性原因,所有外连接SQL语句中,请一律使用LEFT JOIN,禁用RIGHT JOIN

     c) 另外,请注意LEFT JOIN字句中,右边位置表的条件书写位置不同的影响:

     SELECT A.rolename,A.gmt_create,B.nickname FROM gl_role A LEFT JOIN gl_roledetail B ON A.ID=B.roleid AND 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 |

    ----------------+------+

  15. 表连接分页查询的使用

    a) 常规分页语句写法(start:起始记录数,page_offset:每页记录数):SELECT ID,username FROM gl_user WHERE username like ‘%@163.com‘ ORDER BY M.gmt_create LIMIT start, page_offset;

    b) 多表 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.rolename FROM (SELECT ID,username FROM gl_user WHERE username like ‘%@163.com‘ ORDER BY M.gmt_create LIMIT start, page_offset)M,gl_role P WHERE M.ID=P.userid;

       这样写的前提是关联的表之间记录一一对应,否则可能会返回的记录数目少于或多余page_offset的值。

  16. "join"、"in"、"not in"、"exsits"和"not exists"的使用

     a) 比较IN,EXISTS,JOIN

          按效率从好到差排序:

             字段上有索引: EXISTS, IN, JOIN

             字段上没有索引: JOIN, EXISTS ,IN

      b) Anti-Joins: NOT IN ,NOT EXISTS, LEFT JOIN

          按效率从好到差排序:

               字段上有索引: LEFT JOIN, NOT EXISTS, NOT IN

               字段上没有索引: NOT IN, NOT EXISTS, LEFT JOIN

  17. 其它编写规范

     a) 对表的记录进行更新的时候,必须包含对gmt_modified字段的更新;

     b) 不允许在where后添加1=1这样的无用条件,where可以写在prepend属性里,如:

        错误的写法: select count from BD_CONTRACT t where 1=1 <dynamic> ...... </dynamic>

        正确的写法: select count from BD_CONTRACT t <dynamic prepend="where"> ...... </dynamic>

     c) 对大表进行查询时,在SQLMAP中需要加上对空条件的判断语句,具体可在遇到时咨询DBA,如:

     性能上不保险的写法:
     select count from iw_user usr

     <dynamic prepend="where">

     <isNotEmpty prepend="AND" property="userId"> usr.iw_user_id = #userId:varchar# </isNotEmpty>

     <isNotEmpty prepend="AND" property="email"> usr.email = #email:varchar# </isNotEmpty>

     <isNotEmpty prepend="AND" property="certType"> usr.cert_type = #certType:varchar# </isNotEmpty>

     <isNotEmpty prepend="AND" property="certNo"> usr.cert_no = #certNo:varchar# </isNotEmpty>

     </dynamic>

      性能上较保险的写法(防止那些能保证查询性能的关键条件都为空):

      select count from iw_user usr

      <dynamic prepend="where">

      <isNotEmpty prepend="AND" property="userId"> usr.iw_user_id = #userId:varchar# </isNotEmpty>

      <isNotEmpty prepend="AND" property="email"> usr.email = #email:varchar# </isNotEmpty>

      <isNotEmpty prepend="AND" property="certType"> usr.cert_type = #certType:varchar# </isNotEmpty>

      <isNotEmpty prepend="AND" property="certNo"> usr.cert_no = #certNo:varchar# </isNotEmpty>

      <isEmpty property="userId"><isEmpty property="email"> <isEmpty property="certNo"> query not allowed </isEmpty>

      </isEmpty> </isEmpty>

      </dynamic>

     另外,对查询表单的查询控制建议使用web层进行控制而不是客户端脚本(JAVASCRIPT/VBSCRIPT)

     d) 聚合函数常见问题

        1) 不要使用count(1)代替count(*)

        2) count(column_name)计算该列不为NULL的记录条数

        3) count(distinct column_name)计算该列不为NULL的不重复值数量

        4) count()函数不会返回NULL,但sum()函数可能返回NULL,可以使用ifnull(sum(qty),0)来避免返回NULL

        e) NULL的使用

            1) 理解NULL的含义,是"不确定",而不是"空"

            2) 查询时,使用is null或者is not null

            3) 更新时,使用等于号,如:update tablename set column_name = null

二.格式规范

    1.注释说明

         a) 本注释说明主要用于Mysql Client程序及其它SQL文件,其它可作参考;

         b) SQL接受的注释有三种:

          -- 这儿是注释(注意,第2个破折号后面至少跟一个空格符)

              /* 这儿是注释 */

             # 这儿是注释

         c) 下面的例子显示了3种风格的注释:

          mysql> SELECT 1+1; # This comment continues to the end of line

          mysql> SELECT 1+1; -- This comment continues to the end of line

          mysql> SELECT 1 /* this is an in-line comment */ + 1;

          mysql> SELECT 1+ /* this is a multiple-line comment */

  2.缩进

      低级别语句在高级别语句后的,一般缩进4个空格:

       DECLARE

            v_MemberId     VARCHAR(32),

       BEGINSELECT

          admin_member_id INTO v_MemberId

       FROM

          company WHERE id = 10;

      SELECT v_MemberId ;

       END;

      同一语句不同部分的缩进,如果为sub statement,则通常为2个空格,如果与上一句某部分有密切联系的,则缩至与其对齐:

BEGIN FOR v_TmpRec IN (SELECT login_id, gmt_created, -- here indented as column above satus FROM member -- sub statement WHERE site = ‘china‘ AND country=‘cn‘ ) LOOP NULL; END LOOP; END;

3.断行

    a) 一行最长不能超过80字符

    b) 同一语句不同字句之间

    c) 逗号以后空格

    d) 其他分割符前空格

    SELECT concat(offer_name,‘,‘, offer_count as offer_category, id) FROM category WHERE super_category_id_1 = 0;

? 附录:Mysql保留字

     
ADD  DEFAULT  INSERT  NULL  SQL_CALC_FOUND_ROWS 
ALL  DELAYED  INT  NUMERIC  SQL_SMALL_RESULT 
ALTER  DELETE  INT1  ON  SQLEXCEPTION 
ANALYZE  DESC  INT2  OPTIMIZE  SQLSTATE 
AND  DESCRIBE  INT3  OPTION  SQLWARNING 
AS  DETERMINISTIC  INT4  OPTIONALLY  SSL 
ASC  DISTINCT  INT8  OR  STARTING 
ASENSITIVE  DISTINCTROW  INTEGER  ORDER  STRAIGHT_JOIN 
BEFORE  DIV  INTERVAL  OUT  TABLE 
BETWEEN  DOUBLE  INTO  OUTER  TERMINATED 
BIGINT  DROP  IS  OUTFILE  THEN 
BINARY  DUAL  ITERATE  PRECISION  TINYBLOB 
BLOB  EACH  JOIN  PRIMARY  TINYINT 
BOTH  ELSE  KEY  PROCEDURE  TINYTEXT 
BY  ELSEIF  KEYS  PURGE  TO 
CALL  ENCLOSED  KILL  RAID0  TRAILING 
CASCADE  ESCAPED  LABEL  RANGE  TRIGGER 
CASE  EXISTS  LEADING  READ  UNDO 
CHANGE  EXIT  LEAVE  READS  UNION 
CHAR  EXPLAIN  LEFT  REAL  UNIQUE 
CHARACTER  FETCH  LIKE  REFERENCES  UNLOCK 
CHECK  FLOAT  LIMIT  REGEXP  UNSIGNED 
COLLATE  FLOAT4  LINEAR  RELEASE  UPDATE 
COLUMN  FLOAT8  LINES  RENAME  USAGE 
CONDITION  FOR  LOAD  REPEAT  USE 
CONNECTION  FORCE  LOCALTIME  REPLACE  USING 
CONSTRAINT  FOREIGN  LOCALTIMESTAMP  REQUIRE  UTC_DATE 
CONTINUE  FROM  LOCK  RESTRICT  UTC_TIME 
CONVERT  FULLTEXT  LONG  RETURN  UTC_TIMESTAMP 
CREATE  GOTO  LONGBLOB  REVOKE  VALUES 
CROSS  GRANT  LONGTEXT  RIGHT  VARBINARY 
CURRENT_DATE  GROUP  LOOP  RLIKE  VARCHAR 
CURRENT_TIME  HAVING  LOW_PRIORITY  SCHEMA  VARCHARACTER 
CURRENT_TIMESTAMP  HIGH_PRIORITY  MATCH  SCHEMAS  VARYING 
CURRENT_USER  HOUR_MICROSECOND  MEDIUMBLOB  SECOND_MICROSECOND  WHEN 
CURSOR  HOUR_MINUTE  MEDIUMINT  SELECT  WHERE 
DATABASE  HOUR_SECOND  MEDIUMTEXT  SENSITIVE  WHILE 
DATABASES  IF  MIDDLEINT  SEPARATOR  WITH 
DAY_HOUR  IGNORE  MINUTE_MICROSECOND  SET  WRITE 
DAY_MICROSECOND  IN  MINUTE_SECOND  SHOW  X509 
DAY_MINUTE  INDEX  MOD  SMALLINT  XOR 
DAY_SECOND  INFILE  MODIFIES  SPATIAL  YEAR_MONTH 
DEC  INNER  NATURAL  SPECIFIC  ZEROFILL 
DECIMAL  INOUT  NO_WRITE_TO_BINLOG  SQL  FALSE 
DECLARE  INSENSITIVE  NOT  SQL_BIG_RESULT  TRUE 

? Mysql名词解释

  a) PK:Primary Key,主键

  b) UK:Unique Key,唯一性索引

  c) FK:Foreign Key,外键

Labels:

 

mysql数据库设计开发规范,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。