MySQL开发规范

说明,此规范为内部制定的一个给开发人员如何使用MySQL的规范,由Team共同讨论制定,还在不断的完善中,有一些建议或者规定不必定十分合理,后续可能会修改。另外,MySQL版本不断进化,也会致使有一些条款失效,请你们根据自身的状况谨慎参考。html

blackjack ,  roulette ,  slots ,  slots ,  blackjack ,  roulette ,  casino ,  blackjack ,  blackjack ,  blackjack ,  slots

1、 表设计前端

  1. 库名、表名、字段名 必须 使用小写字母,“_”分割。 【FAQ】
  2. 库名、表名、字段名 必须 不超过12个字符。 【FAQ】
  3. 库名、表名、字段名见名知意,建议使用名词而不是动词。 【FAQ】
  4. 建议使用InnoDB存储引擎。 【FAQ】
  5. 存储精确浮点数 必须 使用DECIMAL替代FLOAT和DOUBLE。 【FAQ】
  6. 建议使用UNSIGNED存储非负数值。 【FAQ】
  7. 建议使用INT UNSIGNED存储IPV4。 【FAQ】
  8. 整形定义中不添加长度,好比使用INT,而不是INT(4)。 【FAQ】
  9. 使用短数据类型,好比取值范围为0-80时,使用TINYINT UNSIGNED。
  10. 不建议使用ENUM类型,使用TINYINT来代替。 【FAQ】
  11. 尽量不使用TEXT、BLOB类型。 【FAQ】
  12. VARCHAR(N),N表示的是字符数不是字节数,好比VARCHAR(255),能够最大可存储255个汉字,须要根据实际的宽度来选择N。
  13. VARCHAR(N),N尽量小,由于MySQL一个表中全部的VARCHAR字段最大长度是65535个字节,进行排序和建立临时表一类的内存操做时,会使用N的长度申请内存。 【FAQ】
  14. 表字符集选择UTF8。 【FAQ】
  15. 使用VARBINARY存储变长字符串。 【FAQ】
  16. 存储年使用YEAR类型。
  17. 存储日期使用DATE类型。
  18. 存储时间(精确到秒)建议使用TIMESTAMP类型,由于TIMESTAMP使用4字节,DATETIME使用8个字节。 【FAQ】
  19. 建议字段定义为NOT NULL。 【FAQ】
  20. 将过大字段拆分到其余表中。
  21. 禁止 在数据库中使用VARBINARY、BLOB存储图片、文件等。
  22. 表结构变动须要通知DBA审核。

2、 索引 【FAQ】java

  1. 非惟一索引 必须 按照“idx_字段名称_字段名称[_字段名]”进行命名。
  2. 惟一索引 必须 按照“uniq_字段名称_字段名称[_字段名]”进行命名。
  3. 索引名称 必须 使用小写。
  4. 索引中的字段数 建议 不超过5个。
  5. 单张表的索引数量控制在5个之内。 【FAQ】
  6. 惟一键由3个如下字段组成,而且字段都是整形时,使用惟一键做为主键。
  7. 没有惟一键或者惟一键不符合5中的条件时,使用自增(或者经过发号器获取)id做为主键。
  8. 惟一键不和主键重复。
  9. 索引字段的顺序须要考虑字段值去重以后的个数,个数多的放在前面。
  10. ORDER BY,GROUP BY,DISTINCT的字段须要添加在索引的后面。
  11. 使用EXPLAIN判断SQL语句是否合理使用索引,尽可能避免extra列出现:Using File Sort,Using Temporary。 【FAQ】
  12. UPDATE、DELETE语句须要根据WHERE条件添加索引。
  13. 不建议使用%前缀模糊查询,例如LIKE “%weibo”。
  14. 对长度过长的VARCHAR字段创建索引时,添加crc32或者MD5 Hash字段,对Hash字段创建索引。 【FAQ】
  15. 合理建立联合索引(避免冗余),(a,b,c) 至关于 (a) 、(a,b) 、(a,b,c)。
  16. 合理利用覆盖索引。 【FAQ】
  17. SQL变动须要确认索引是否须要变动并通知DBA。

3、 SQL 语句python

  1. 使用prepared statement,能够提供性能而且避免SQL注入。
  2. SQL语句中IN包含的值不该过多。
  3. UPDATE、DELETE语句不使用LIMIT。 【FAQ】
  4. WHERE条件中 必须 使用合适的类型,避免MySQL进行隐式类型转化。 【FAQ】
  5. SELECT语句只获取须要的字段。
  6. SELECT、INSERT语句 必须 显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。 【FAQ】
  7. 使用SELECT column_name1, column_name2 FROM table WHERE [condition]而不是SELECT column_name1 FROM table WHERE [condition]和SELECT column_name2 FROM table WHERE [condition]。
  8. WHERE条件中的非等值条件(IN、BETWEEN、<、<=、>、>=)会致使后面的条件使用不了索引。
  9. 避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一块儿。
  10. INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不该过多。
  11. 避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一块儿,而且MySQL的存储过程、触发器、函数中存在必定的bug。
  12. 避免使用JOIN。
  13. 使用合理的SQL语句减小与数据库的交互次数。 【FAQ】
  14. 不使用ORDER BY RAND(),使用其余方法替换。 【FAQ】
  15. 建议使用合理的分页方式以提升分页的效率。 【FAQ】
  16. 统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。
  17. 在从库上执行后台管理和统计类型功能的QUERY。 【FAQ】

4、 散表mysql

  1. 对于字段类型简单,字段数很少表,单表数据量建议控制在5000w如下。
  2. 能够结合使用hash、range、lookup table进行散表。
  3. 散表若是使用md5(或者相似的hash算法)进行散表,表名后缀使用16进制,好比user_ff。
  4. 推荐 使用CRC32求余(或者相似的算术算法)进行散表,表名后缀使用数字,数字 必须 从0开始并等宽,好比散100张表,后缀从00-99。
  5. 使用时间散表,表名后缀 必须 使用特定格式,好比按日散表user_2011020九、按月散表user_201102。

5、 其余linux

  1. 批量导入、导出数据须要DBA进行审查,并在执行过程当中观察服务。
  2. 批量更新数据,如update,delete 操做,须要DBA进行审查,并在执行过程当中观察服务。
  3. 产品出现非数据库平台运维致使的问题和故障时,如前端被抓站,请及时通知DBA,便于维护服务稳定。
  4. 业务部门程序出现bug等影响数据库服务的问题,请及时通知DBA,便于维护服务稳定。
  5. 业务部门推广活动,请提早通知DBA进行服务和访问评估。
  6. 若是出现业务部门人为误操做致使数据丢失,须要恢复数据,请在第一时间通知DBA,并提供准确时间,误操做语句等重要线索。

———————————————————————————————————————————————————————————————-redis

FAQ算法

1-1.库名、表名、字段名 必须 使用小写字母,“_”分割。 
sql

a) MySQL有配置参数lower_case_table_names,不可动态更改,linux系统默认为0,即库表名以实际状况存储,大小写敏感。若是是1,以小写存储,大小写不敏感。若是是2,以实际状况存储,但以小写比较。数据库

b) 若是大小写混合用,可能存在abc,Abc,ABC等多个表共存,容易致使混乱。

c) 字段名显示区分大小写,但实际使用不区分,即不能够创建两个名字同样但大小写不同的字段。

d) 为了统一规范, 库名、表名、字段名使用小写字母。

back

1-2.库名、表名、字段名 必须 不超过12个字符。

库名、表名、字段名支持最多64个字符,但为了统一规范、易于辨识以及减小传输量,必须不超过12字符。

back

1-3.库名、表名、字段名见名知意,建议使用名词而不是动词。

a) 用户评论可用表名usercomment或者comment。

b) 库表是一种客观存在的事物,一种对象,因此建议使用名词。

back

1-4.建议使用InnoDB存储引擎。

a) 5.5之后的默认引擘,支持事务,行级锁,更好的恢复性,高并发下性能更好,对多核,大内存,ssd等硬件支持更好。

b) 具体比较可见附件的官方白皮书。

back

1-5.存储精确浮点数 必须 使用DECIMAL替代FLOAT和DOUBLE。

a) mysql中的数值类型(不包括整型): 
IEEE754浮点数: float (单精度) , double 或 real (双精度) 
定点数: decimal 或 numeric 
单精度浮点数的有效数字二进制是24位,按十进制来讲,是8位;双精度浮点数的有效数字二进制是53位,按十进制来讲,是16 位 
一个实数的有效数字超过8位,用单精度浮点数来表示的话,就会产生偏差!一样,若是一个实数的有效数字超过16位,用双精度浮点数来表示,也会产生偏差 
b) IEEE754标准的计算机浮点数,在内部是用二进制表示的,但在将一个十进制数转换为二进制浮点数时,也会形成偏差,缘由是否是全部的数都能转换成有限长度的二进制数。 
即一个二进制能够准确转换成十进制,但一个带小数的十进制不必定可以准确地用二进制来表示。

实例: 
drop table if exists t;

create table t(value float(10,2));

insert into t values(131072.67),(131072.68);

select value from t;

+———–+

| value |

+———–+

| 131072.67 |

| 131072.69 |

+———–+

back

1-6.建议使用UNSIGNED存储非负数值。

一样的字节数,存储的数值范围更大。如tinyint 有符号为 -128-127,无符号为0-255

back

1- 7. 如何使用INT UNSIGNED存储ip?

使用INT UNSIGNED而不是char(15)来存储ipv4地址,经过MySQL函数inet_ntoa和inet_aton来进行转化。Ipv6地址目前没有转化函数,须要使用DECIMAL或者两个bigINT来存储。例如:

SELECT INET_ATON(‘209.207.224.40′);

3520061480

SELECT INET_NTOA(3520061480);

209.207.224.40

back

1-8. INT[M],M值表明什么含义?

注意数值类型括号后面的数字只是表示宽度而跟存储范围没有关系,好比INT(3)默认显示3位,空格补齐,超出时正常显示,python、java客户端等不具有这个功能。

back

1-10.不建议使用ENUM、SET类型,使用TINYINT来代替。

a) ENUM,有三个问题:添加新的值要作DDL,默认值问题(将一个非法值插入ENUM(也就是说,容许的值列以外的字符串),将插入空字符串以做为特殊错误值),索引值问题(插入数字实际是插入索引对应的值)

实例:

drop table if exists t;

create table t(sex enum(‘0′,’1′));

insert into t values(1);

insert into t values(‘3′);

select * from t;

+——+

| sex |

+——+

| 0 |

| |

+——+

2 rows in set (0.00 sec)

back

1-11.尽量不使用TEXT、BLOB类型。

a) 索引排序问题,只能使用max_sort_length的长度或者手工指定ORDER BY SUBSTRING(column, length)的长度来排序

b) Memory引擘不支持text,blog类型,会在磁盘上生成临时表

c) 可能浪费更多的空间

d) 可能没法使用adaptive hash index

e) 致使使用where没有索引的语句变慢

back

1-13. VARCHAR中会产生额外存储吗?

VARCHAR(M),若是M<256时会使用一个字节来存储长度,若是M>=256则使用两个字节来存储长度。

back

1-14.表字符集选择UTF8。

a) 使用utf8字符集,若是是汉字,占3个字节,但ASCII码字符仍是1个字节。 
b) 统一,不会有转换产生乱码风险 
c) 其余地区的用户(美国、印度、台湾)无需安装简体中文支持,就能正常看您的文字,而且不会出现乱码 
d) ISO-8859-1编码(latin1)使用了单字节内的全部空间,在支持ISO-8859-1的系统中传输和存储其余任何编码的字节流都不会被抛弃。即把其余任何编码的字节流看成ISO-8859-1编码看待都没有问题,保存的是原封不动的字节流。

back

1-15.使用VARBINARY存储变长字符串。

二进制字节流,不存在编码问题

back

1-18. 为何建议使用TIMESTAMP来存储时间而不是DATETIME?

DATETIME和TIMESTAMP都是精确到秒,优先选择TIMESTAMP,由于TIMESTAMP只有4个字节,而DATETIME8个字节。同时TIMESTAMP具备自动赋值以及自动更新的特性。

如何使用TIMESTAMP的自动赋值属性?

a) 将当前时间做为ts的默认值:ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP。

b) 当行更新时,更新ts的值:ts TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP。

c) 能够将1和2结合起来:ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。

back

1-19.建议字段定义为NOT NULL。

a)若是null字段被索引,须要额外的1字节

b)使索引,索引统计,值的比较变得更复杂

c)可用0,”代替

d)若是是索引字段,必定要定义为not null

back

1-21. 禁止 在数据库中使用VARBINARY、BLOB存储图片、文件等。

采用分布式文件系统更高效

back

2. 为何MySQL的性能依赖于索引?

MySQL的查询速度依赖良好的索引设计,所以索引对于高性能相当重要。合理的索引会加快查询速度(包括UPDATE和DELETE的速度,MySQL会将包含该行的page加载到内存中,而后进行UPDATE或者DELETE操做),不合理的索引会下降速度。

MySQL索引查找相似于新华字典的拼音和部首查找,当拼音和部首索引不存在时,只能经过一页一页的翻页来查找。当MySQL查询不能使用索引时,MySQL会进行全表扫描,会消耗大量的IO。

back

2-5. 为何一张表中不能存在过多的索引?

InnoDB的secondary index使用b+tree来存储,所以在UPDATE、DELETE、INSERT的时候须要对b+tree进行调整,过多的索引会减慢更新的速度。

back

2-11. EXPLAIN语句

EXPLAIN 语句(在MySQL客户端中执行)能够得到MySQL如何执行SELECT语句的信息。经过对SELECT语句执行EXPLAIN,能够知晓MySQL执 行该SELECT语句时是否使用了索引、全表扫描、临时表、排序等信息。尽可能避免MySQL进行全表扫描、使用临时表、排序等。详见 官方文档 。

back

2-13.不建议使用%前缀模糊查询,例如LIKE “%weibo”。

会致使全表扫描

2-14. 如何对长度大于50的VARCHAR字段创建索引?

下面的表增长一列url_crc32,而后对url_crc32创建索引,减小索引字段的长度,提升效率。

  • CREATE TABLE url(

……

url VARCHAR(255) NOT NULL DEFAULT 0, 
url_crc32 INT UNSIGNED NOT NULL DEFAULT 0,

……

index idx_url(url_crc32)

)

back

2-16. 什么是覆盖索引?

InnoDB 存储引擎中,secondary index(非主键索引)中没有直接存储行地址,存储主键值。若是用户须要查询secondary index中所不包含的数据列时,须要先经过secondary index查找到主键值,而后再经过主键查询到其余数据列,所以须要查询两次。

覆盖索引的概念就是查询能够经过在一个索引中完成,覆盖索引效率会比较高,主键查询是自然的覆盖索引。

合理的建立索引以及合理的使用查询语句,当使用到覆盖索引时能够得到性能提高。

好比SELECT email,uid FROM user_email WHERE uid=xx,若是uid不是主键,适当时候能够将索引添加为index(uid,email),以得到性能提高。

back

3-3.UPDATE、DELETE语句不使用LIMIT。

a) 可能致使主从数据不一致

b) 会记录到错误日志,致使日志占用大量空间

back

3-4. 为何须要避免MySQL进行隐式类型转化?

由于MySQL进行隐式类型转化以后,可能会将索引字段类型转化成=号右边值的类型,致使使用不到索引,缘由和避免在索引字段中使用函数是相似的。

back

3-6. 为何不建议使用SELECT *?

增长不少没必要要的消耗(cpu、io、内存、网络带宽);减小了使用覆盖索引的可能性;当表结构发生改变时,前端代码可能也须要更新。

back

3-13. 如何减小与数据库的交互次数?

使用下面的语句来减小和db的交互次数:

INSERT … ON DUPLICATE KEY UPDATE

REPLACE

INSERT IGNORE

INSERT INTO values(),()如何结合使用多个纬度进行散表散库?

例如message,先按照crc32(message_id)%16将message散到16个库中,而后针对每一个库中的表,一天生成一张新表。

back

3-14. 为何不能使用ORDER BY rand()?

由于ORDER BY rand()会将数据从磁盘中读取,进行排序,会消耗大量的IO和CPU,能够在程序中获取一个rand值,而后经过在从数据库中获取对应的值。

back

3-15. MySQL中如何进行分页?

假若有相似下面分页语句:

SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;

这种分页方式会致使大量的io,由于MySQL使用的是提早读取策略。

推荐分页方式:

SELECT * FROM table WHERE TIME<last_TIME ORDER BY TIME DESC LIMIT 10.

SELECT * FROM table inner JOIN(SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t USING(id)

back

3-17.为何避免使用复杂的SQL?

拒绝使用复杂的SQL,将大的SQL拆分红多条简单SQL分步执行。缘由:简单的SQL容易使用到MySQL的query cache;减小锁表时间特别是MyISAM;可使用多核cpu。

back

2. InnoDB存储引擎为何避免使用COUNT(*)?

InnoDB表避免使用COUNT(*)操做,计数统计实时要求较强可使用memcache或者redis,非实时统计可使用单独统计表,定时更新。

参照

1. Optimization and Indexes

2. Data Types

 

 

原文  http://www.iamcjd.com/?p=1237

相关文章
相关标签/搜索