1、数据库命名规范,统一:vip_xxxx
0、表一旦设计好,字段只允许增加,不允许减少(drop column)
1、统一使用INNODB存储引擎,UTF8编码(整个数据库的编码统一为utf8_general_ci,为此不需要建立表的DDL加上特别CHARACTER SET utf8 COLLATE utf8_general_ci);
2、需在设计阶段考虑如果访问量非常大,且不做scale out表拆分的话,需读写分离,但读写分离注意主从复制有延迟的可能性;
3、禁用Stored procedure (包括存储过程,函数,触发器);
4、UUID(),USER()这样的MYSQL INSIDE函数对于复制来说是很危险的,会导致主备数据不一致,重要的是会严重影响mysql性能,禁止使用。
5、表必须有主键,建议统一由Auto-Increment字段生成整型,不建议使用组合主键,自增id只作为虚拟主键,不建议与业务数据处理有关联关系,如果把控不好,会有问题(案例:AUTO_INCREMENT主键字段不要与业务有关联关系)
6、库名、表名、字段名、索引名必须使用小写字母;
7、多表join的时候,写SQL的时候一定要给每个字段指定表名做前缀;如: select a.id,a.name from test1 a, test2 b where a.id=b.id
8、如果应用使用的是长连接,应用必须具有自动重连的机制。但请避免每执行一个SQL去检查一次DB可用性;
9、如果应用使用的是长连接,应用应该具有连接的TIMEOUT检查机制,及时回收长时间没有使用的连接,TIMEOUT时间一般建议为20min。
10、存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,如金额等。
11、尽量用单表查询,避免多表JOIN。
12、表名列名必须有注释(必须加上COMMENT '<字段扼要解说>'),表结构变更须由库表OWNER所在团队发起,
13、SQL语句必须采用preparedStatement技术, 如果编程语言不支持preparedStatement技术,需要做好特殊字符过滤,如不要前后有空串等
14、尽可能不要使用TEXT、BLOB、char,请使用VARCHAR(N),N表示的是字符数不是字节数,比如VARCHAR(255),可以最大可存储255个汉字,需要根据实际的宽度来选择N,请注意同一表中,所有varchar字段的长度加起来,不能大于65535。
15、每张表数据量建议控制在千万级别行以下,为此设计阶段需考虑数据的归档。
16、如果字段只有true or false,请使用tinyint(数值范围-128~127),如模块分类:1订单 2商品;删除标志 0正常,1删除;状态 1为可选,2为不可选等等
17、存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节,同时TIMESTAMP具有自动赋值以及自动更新的特性。
18、每个字段的默认值不能用NULL,禁止default NULL,数字类型default 0,字符类型default '';
19、关键业务数据表,建议有create_time和last_update_time,方便后期数据分析,如订单表,库存表;
20、MySQL上,禁止使用select col、col from table where id in (select col from table)这样的子查询;
21、需要多表join的字段(禁止多于两表join),数据类型保持绝对一致。
22、关键业务数据表,如订单表,用户信息表,钱包支付信息等,禁止硬删除,必须软删除,加上is_deleted字段,标注这条记录的状态。
23、加字段禁止使用after,因为你不确定全局代码里面(如其他团队使用你的表)是否都insert into table(col,col,col。。。) value,如果你在中间插一个字段,就导致数据偏移的问题了,影响可大可小,同样select * 的也可能会影响数值的偏移,所以才要求,禁止after,必须带default(第18点要求)。
24、线上MySQL是忽略大小写的(配置了lower_case_table_names=1),如下面的例子:
事务的处理标准
0、一个事务,处理的行数不能超过1000 rows/s (曾经发生过的案例,超出了会导致主从复制延迟的问题
1、禁止一些框架或定制化的底层类等使用set autocommit=0;set autocommit=1;这样控制事务,应该由程序把控,需要时begin;操作完后及时commit2、要合理使用事务,例子:购物车如下的 事务处理,可以更好的优化。
下面的事务可以更好的优化,start transection后,
select
1次,
insert
2次,seletc 1次,
update
1次,总:2 QPS,3 TPS,然后没有库存
rollback
,这种在正常情况下没有问题的,按如小米这种极端抢购的情况下,会大大浪费了购物车数据库的CPU资源
########################################################
#如用户ID:72965761,一次事务的操作
########################################################
Query
SET
NAMES utf8
Query start
transaction
Query
SELECT
`cart`.`id`, `cart`.`user_id`, `cart`.`warehouse`, `cart`.`add_time`, `cart`.`expire_time`, `cart`.`add_type`
FROM
`cart`
WHERE
(user_id =72965761
OR
user_id=-72965761)
AND
(warehouse =
'VIP_NH'
)
AND
(expire_time >= 1408084591)
ORDER
BY
`id`
DESC
LIMIT 1
Query
INSERT
IGNORE
INTO
`cart` (`user_id`, `warehouse`, `add_time`, `expire_time`, `add_type`)
VALUES
(72965761,
'VIP_NH'
, 1408084591, 1408085791, 0)
Query
INSERT
IGNORE
INTO
`user_cart` (`cart_id`, `user_id`, `product_id`, `
size
`, `num`, `add_time`, `warehouse`, `product_info`, `brand_id`, `suite_id`, `active_id`, `active_limit_id`, `active_no`, `add_type`)
VALUES
(442034, 72965761,
'30014072'
,
'78845863'
,
'1'
, 1408084591,
'VIP_NH'
,
''
,
'210123'
, 0, 0, 0,
''
, 0)
Query
SELECT
`user_cart`.`id`
FROM
`user_cart`
WHERE
(cart_id = 442034
AND
flag =
'0'
)
Query
UPDATE
`user_cart`
SET
`add_time` = 1408084591
WHERE
id
in
(
'711744'
)
AND
flag =
'0'
Query
rollback
Quit
索引使用标准
1、非唯一索引建议使用“idx_表缩写名称_字段缩写名称”进行命名。
2、唯一索引建议使用“uniq_表缩写名称_字段缩写名称”进行命名。
3、索引名称必须使用小写。
4、唯一键不和主键重复。
5、索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面,就是数据分布。
6、使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,Using Temporary。
7、UPDATE、DELETE语句需要根据WHERE条件添加索引。
8、合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。
9、合理利用覆盖索引。比如SELECT email,uid FROM user_email WHERE uid=xx,如果uid不是主键,适当时候可以将索引添加为index(uid,email),以获得性能提升。
约束设计
a) 主键的内容不能被修改。
b) 外键约束一般不在数据库上创建,只表达一个逻辑的概念,由程序控制。
d) 禁用数据库外键
命名
a) 主键约束:默认PRIMARY;
b) unique约束:UK_<column_name>
c) check约束: CK_<column_name>
d) 外键约束: 业务禁用
SQL语句标准
0、禁止多于3表的join。
1、使用prepared statement,可以***能并且避免SQL注入。
2、SELECT语句只获取需要的字段,禁止使用SELECT * FROM语句,这是有效防止新增字段对应用逻辑的影响,还能减少对性能的影响;
3、INSERT语句必须显式的指明字段名称,不使用INSERT INTO table value()。
4、禁止在where子句中对字段施加函数,如to_date(add_time)>xxxxx,应改为:add_time >= unix_timestamp(date_add(str_to_date('20130227','%Y%m%d'),interval - 29 day))
5、UPDATE、DELETE语句不使用LIMIT。
6、写到应用程序里的SQL语句,禁止一切DDL操作,如对这些权限有要求,必需与DBA协商同意方可使用
7、WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化,如ISENDED=1,字段类型是tinyint,那么不能是ISENDED=‘1’。
8、避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。
9、INSERT语句使用batch提交。
10、避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。
11、使用合理的SQL语句减少与数据库的交互次数。
12、不使用ORDER BY RAND(),使用其他方法替换。
13、建议使用合理的分页方式以提高分页的效率。
14、InnoDB表避免使用COUNT(*)操作,计数统计实时要求较强可以使用memcache或者redis,非实时统计可以使用单独统计表,定时更新。
15、不建议使用%前缀模糊查询,例如LIKE “%weibo”。
16、避免多余的排序。使用GROUP BY 时,默认会进行排序,当你不需要排序时,可以使用order by null,例如Select a.OwnerUserID,count(*) cnt from DP_MessageList a group by a.OwnerUserID order by null;
每个整数类型的存储和范围。
类型 | 字节 | 最小值 | 最大值 |
(带符号的/无符号的) | (带符号的/无符号的) | ||
TINYINT | 1 | -128 | 127 |
0 | 255 | ||
SMALLINT | 2 | -32768 | 32767 |
0 | 65535 | ||
MEDIUMINT | 3 | -8388608 | 8388607 |
0 | 16777215 | ||
INT | 4 | -2147483648 | 2147483647 |
0 | 4294967295 | ||
BIGINT | 8 | -9223372036854775808 | 9223372036854775807 |
0 | 18446744073709551615 |