找回密码
 注册
关于网站域名变更的通知
查看: 668|回复: 3
打印 上一主题 下一主题

[研发人员培养] 数据库设计和研发规范

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2021-9-8 09:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
一.  基础规范& b: O8 w  D2 Q3 ~+ y! T
所有表都需要添加注释
+ j" x! Y* L) {2 d使用comment从句添加表和列的备注,从一开始就做好数据字典维护。* b  m; E! }5 b. U& }1 @( }/ y

, P, G2 P. I. J- N单表数据量建议控制在500万以内
4 H: m' F) n% T! X过大会给备份和恢复带来困难,可用历史数据归档(用于日志数据),分库分表(用于业务数据)等手段来控制数据量大小。
: U# N7 {8 a/ Z" i& t3 i# p: G
2 s7 x  M! }! W8 _不在数据库中存储图、文件等二进制数据7 P% n  a6 I" C  A2 X9 I
图或文件IO操作耗时,通常存储于文件服务器,数据库只存储文件地址信息。
1 H& t! I4 s6 e$ o5 e0 @( N7 v% p5 P+ T# P0 M
尽量冷热数据分离,减小表的宽度6 v$ ]: ]/ k8 i3 X& g% H4 m! T
把不常用且占宽大的字段从热表中分离可独立存储,每一行数据大小不超过65535字节。
6 W. i) x$ o. y6 h) E' h6 b2 ^, @, f% j% J  i- \. W1 b* w7 a8 d
禁止测试、开发环境直连线上数据库- Q: p0 r0 M$ |9 g( D

- |+ b, [' Y# w2 o二、命名规范
: \0 n/ k( W% B' }/ T# @0 X& L% S- a/ K7 b2 S. V8 r- Z$ d
库名、表名、字段名必须使用小写字母,并采用下划线分割* V( x$ t* `* [( E8 R
MySQL配置参数lower_case_table_names=1,即库表名以小写存储,大小写不敏感。如果是0,则库表名以实际情况存储,大小写敏感;如果是2,以实际情况存储,但以小写比较。如果大小写混合使用,可能存在abc,Abc,ABC等多个表共存,容易导致混乱。
. h/ a' w+ m8 c! P! x% m0 w9 Q: G; Y* v7 L
库名、表名、字段名不要超过32个字符,需见名知意易于辨识# Z$ A, l, b1 C1 |# y; V' B, Z
库名、表名、字段名支持最多64个字符,但为了减少传输量,禁止超过32个字符。+ N) X& g8 m! f3 C

6 W0 ]. u- Y6 f& ?: d" D库名、表名、字段名禁止使用MySQL保留字
7 E% d4 J8 V2 M  R当库名、表名、字段名等含有保留字时,SQL语句必须用反引号引用属性名称,这将使SQL语句书写、SHELL脚本中变量的转义变得非常复杂。, _' r/ \$ z: |" H$ C. s1 e
/ g; Z5 J: m9 e& w' ~
备份库、表必须以bak为前缀,并以日期为后缀# i5 s( D' @0 Z3 r1 w3 \, P! s
形如:bak_user_account_20190313: N4 y7 O6 q7 Q, a5 M2 n! G" A
% H# d+ I; ?6 Y0 v( j4 ^
索引的命名$ I7 N, a) b$ L: y7 a8 B
主键索引名为 pk_字段名;唯一索引名为 uk _字段名;普通索引名则为 idx_字段名。7 M6 p& T; H( a9 y  e4 V
2 N) I' I. n+ O% e+ U

4 S7 W8 b* J6 o4 n8 d3 w6 a8 w6 z三、字段设计规范
' n) K# z9 @$ B7 B6 i' r! e$ t9 |4 x2 X+ T2 z" e: A% y
优先选择符合存储需要的最小的数据类型$ |, w5 }7 @( a5 Q$ j+ e
列的字段类型越大,建立索引占据的空间就越大,使得一个页中的索引越少,IO次数增加,影响性能,能用int的就不用char或者varchar,能用tinyint的就不用int。状态status、类型type等字段推荐使用tinytint或者smallint类型节省存储空间;使用 UNSIGNED 存储非负数值;使用tinyint来代替 enum和boolean;存储 ip 最好用 int存储而非 char(15)。( E8 R! W. D8 N' [+ }
* `5 O6 ?$ S8 r
不推荐使用blob,text等类型
) P  e5 u) `: N, S, _blob,text是为了存储极大的字符串而设计的数据类型,采用二进制与字符串方式存储,该数据类型不能设置默认值、不便于排序、不便于建立索引,varchar的性能会比text高很多,如果非要使用,建议将这种数据分离到单独的拓展表中。
; ]% _4 t$ L& S5 n' t) @
8 a% Q" R  Z9 I" c/ d6 a3 i% N3 j禁止使用字符串来存储日期型数据! v4 }. N$ |3 F% g
一是无法使用日期函数计算比较,二是因为字符串存储要占更多的内存空间,datetime占8字节,timestamp是以int存储,占4字节。5 e9 B6 C! V  {, l
, Q7 A- X7 A8 o# D
用DECIMAL代替FLOAT和DOUBLE存储精确浮点数
. J  B- u- y4 z1 _5 [- {Decimal类型为精准浮点数,float 和 double 都有精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。+ P% P. j# G" y: G, O0 z  R
& E. Z' b) q' s8 k9 Q
必须把字段定义为NOT NULL并设默认值2 n& t1 Q, `: y2 L+ ~3 C: ^, }" C
一是NULL需要更多的存储空间,二是NULL的列可能索引实效,三是NULL只能采用IS NULL或者IS NOT NULL,而在=/!=/in/not in时有大坑。
' m: o2 g( |% ?0 g& d3 f; ?3 r6 y9 A8 d
使用varchar(20)存储手机号,不要使用整数
; N3 f" e) q% S) Y/ P% O一是牵扯到国家代号,可能出现+/-/()等字符,例如+86,二是varchar可以模糊查询,例如like ‘138%’
1 y8 p) [1 p% z) Z1 C3 O
( N2 W6 \/ T$ W8 u# G6 x根据业务区分使用char/varchar1 t$ N: e- g7 b* V8 ]$ w5 l
字段长度固定,或者长度近似的业务场景,适合使用char,能够减少碎片,查询性能高
8 Y% @$ u$ W  s$ ^) q. D! D5 I% y9 h1 }8 J) m( r7 J  I. a
字段长度相差较大,或者更新较少的业务场景,适合使用varchar。4 b7 |  J4 q( X! O" W# _& j
! c: r- ?: E# A: a) l0 e9 x" w! I. G
禁止在数据库中存储明文密码,把密码加密后存储% F+ w+ w1 F9 O! x* s
尽量不使用外键
- j+ B) [5 O; C" c6 s7 f3 k建议在应用层实现外键的逻辑, 外键与级联更新不适合高并发场景,降低插入性能,大并发下容易产生死锁。
. L4 U2 \# l) C( a
  o0 T& w+ i7 e5 l8 f+ {核心表必须有行数据的创建时间和最后更新时间
0 u: O, Q* b0 i% a- U' C核心表(如用户表,金钱相关的表)必须有行数据的创建时间字段create_time和最后更新时间字段update_time,便于查问题。
; k( R+ P4 ~* s1 u+ d
! l/ z7 S4 ?! q- o, K( G) n
8 `; |  Y7 F8 y- e' r四、索引设计规范
0 T* U' i+ d8 R0 O9 K+ l3 y2 E
, \* O8 M$ Q% j) |MySQL的查询速度依赖良好的索引设计,因此索引对于高性能至关重要,合理的索引会加快查询速度,不合理的索引会降低速度。
0 f6 |) V6 |2 P" O
0 B/ L+ g7 X! W- J" X7 ^1 s6 e索引其实就是一种数据结构(哈希表、树等),不同类型的索引有着不同的数据结构和功能。0 ?- M6 ^$ ?7 g$ l6 A0 f) N6 o

% G$ X, e7 b$ m# k: O索引的作用是加速查询速度,维护数据的约束性(完整性、一致性)。对于加速查询,使用索引不一定是最好的选择,小表就直接全表扫描,中到大表就建索引,超大表就分区分表,要做好索引带来的好处和维护索引的成本之间的权衡。6 _' @$ c7 I% z8 ?! @+ Y# ~. f
3 B5 |3 }. P- D" y
单表的索引数建议不超过 5 个,单个索引中的字段数建议不超过 5 个
/ D: e1 u$ \1 o! x3 g! `9 V8 _太多就起不到过滤作用了,索引也占空间,管理也耗资源。
' @4 g# x* X$ B. d  P+ i9 p6 K/ i; F2 e% E( m- Y1 \6 {
对字符串使用前缀索引,前缀索引长度不超过8个字符( B! j0 A4 ~0 C2 b* h" S- B; L
不要索引blob/text等字段,不要索引大型字段,这样做会让索引占用太多的存储空间。
9 M" z- H" \/ p* X& E$ `" Z4 r7 {8 _
前缀索引就是对文本的前几个字符建立索引,前缀索引能有效减小索引文件的大小,提高索引的速度。但是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用作覆盖索引(Covering Index)
7 I. t8 x, T9 Q- z( k5 c
& C8 @  e- X1 |: Z, i0 N重要的SQL必须被索引,核心SQL优先考虑覆盖索引
3 o/ c+ q% }" e0 R7 fUPDATE、DELETE 语句的 WHERE 条件列;ORDER BY、GROUP BY、DISTINCT 的字段;多表 JOIN 的字段。覆盖索引可以避免Innodb表进行索引的二次查询,把随机IO变成顺序IO,加快查询效率。4 \9 `7 q# |4 C" d

6 X! W; \2 M7 e3 t1 x5 e) w联合索引区分度最大的字段放在前面) b# ^1 g  w8 F6 a3 ]3 t2 A
选择筛选性更优的字段放在最前面,比如userid,carid等,type,status等筛选性一般不建议放在最前面。索引根据左前缀原则,当建立一个联合索引(a,b,c),则查询条件里面只有包含(a)或(a,b)或(a,b,c)的时候才能走索引,(a,c)作为条件的时候只能使用到a列索引,所以这个时候要确定a的返回列一定不能太多,不然语句设计就不合理,(b,c)则不能走索引。
1 F6 E8 y1 P, v# ~7 M# p! j: i+ e  P4 O! x' C
业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引: t) a% l3 l- l4 L1 |
不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明' B9 N- x, G  v! A" d: f
+ u( ^+ X3 A# D& e$ G
显的; 另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
6 P4 H) O4 R1 y4 ^8 t- m8 T& r% Z
6 ~+ e3 s6 \' _! d& {4 dInnoDB 和 MyISAM 存储引擎表,索引类型必须为BTREE9 h& g0 u3 D2 T1 D
MEMORY表可以根据需要选择 HASH 或者 BTREE 类型索引。
1 a8 ~  c/ D( \6 Z6 p4 r+ u# l& K, R( a% O1 B
MYSQL 中索引的限制
: H: B! s7 C8 |6 l+ z# L. VMYISAM 存储引擎索引长度的总和不能超过 1000 字节) A% p4 b7 ~& \1 A9 K9 q( A
) |( c, Z. C( _" w
BLOB 和 TEXT 类型的列只能创建前缀索引
* H. ?" V+ b: S& i1 c; c& c  L* d7 G) m# n
使用不等于 (!= 或者 <>) 的时候, MYSQL 无法使用索引; `; Y# C  A; M+ e4 {& W
7 m1 ?+ v0 {1 M
过滤字段使用函数运算 (如 abs (column)) 后, MYSQL无法使用索引
' X1 m. C. |2 h, j1 b7 B
  K+ U4 G" u4 ~' ^7 ~join语句中join条件字段类型不一致的时候MYSQL无法使用索引4 n1 p1 P# [6 y. m6 [& W% c* h. C

" P/ H9 s4 D! I2 H( s使用 LIKE 操作的时候如果条件以通配符开始 (如 ‘%abc…’)时, MYSQL无法使用索引  z6 A! d) X) L

5 N$ a3 I( }2 }: I2 i/ ]使用非等值查询的时候, MYSQL无法使用 Hash 索引。7 F  Z& [$ T  @0 g1 g0 ^: j
" |; ?: f: B: Z+ f: i) z
3 c/ b( y8 }# D
五、SQL查询规范
( Z7 {) l  s5 h, `3 e
: W  }2 p. w' K; T3 D% W3 }按需索取拒绝 select *
( G2 g% i" [# f2 X/ l8 f无法索引覆盖,回表操作,IO增加;额外的内存负担,大量冷数据灌入innodb_buffer_pool_size,降低查询命中率;额外的网络传输开销。+ \! n2 N3 V$ b2 e, G' ^/ h9 O+ E) x, P) o

2 Z1 O3 h5 S# a% M! J# K$ H* B超过三个表禁止 join
( }8 ~" C1 l5 L! j1 O需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段有索引。+ p! A, ]1 b2 B0 T$ w+ j6 f1 ~

3 w8 c6 o! U' ]' _' O  w/ \# e涉及到复杂sql时,须用explain检验索引设计
8 s* V: ^3 z1 O对应同一列进行 or 判断时,使用 in 代替 or8 ^6 z/ u+ x0 f1 W, p
in 的值不要超过 500 个, in 操作可以更有效的利用索引,or 大多数情况下很少能利用到索引。, `/ `' i4 p% o7 v0 `/ d; c

0 ?: _( W5 z, G; ?, V8 U' Uin 操作能避免则避免
, @0 R/ S: v7 b6 Y0 I& J6 W' W, e若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内。
5 |5 L8 ~0 W6 n0 @1 o+ v: J8 x; w, F+ c7 G5 \
WHERE从句中禁止对列进行函数转换和计算
' J4 o$ `: i% |对列进行函数转换或计算时会导致无法使用索引。
0 }" ^( Q4 E7 d
4 a$ }" i5 ?# R5 _count(列名)或 count(常量) 替代不了 count(*)
. b! b4 x8 V; ]count(*)是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无,
* }1 ]' E) G9 Z. R6 ]9 u
# c5 a# L, P" t6 e4 a% Tcount(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
6 N5 G6 ]! ?2 x! W; a$ s+ c- R9 M) {; n
不要使用UNION,推荐使用UNION ALL% u8 h: e. x, c1 G! V
因为union all不需要去重,节省数据库资源,提高性能,另外子句个数限制在5个以内。
" E9 g6 R6 G" t) I5 J3 V( C$ N
/ c0 P# `/ a* G" r禁止使用 order by rand() 进行随机排序0 d2 F6 n5 g3 N/ o1 p
会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的 CPU 和 IO 及内存资源,推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。5 @7 P/ ~7 |* ~5 w6 ~/ j

% K$ L  W2 t: o* x4 @不得使用外键与级联,一切外键概念必须在应用层解决& S' J6 q) A# F/ _
以学生和成绩的关系为例,学生表中的 student_id是主键,那么成绩表中的 student_id则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新, 即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群; 级联更新是强阻塞,存在数据库更新风暴的风险;而且外键影响数据库的插入速度。- B9 B  I$ ?( y- A

" W2 l8 f% N; C1 V# f' \使用合理的分页方式以提高分页效率1 s# c/ A4 w* [- S7 g3 g! [
不推荐 SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;  U/ P6 }3 V( K+ Q) Z% M+ _7 ?
/ B4 |8 |8 q8 N
原因:会导致大量的io,因为MySQL使用的是提前读取策略
* c* D7 f% {9 A! J* S0 k- w# t5 F# V1 l  C, b- ?
推荐:SELECT * FROM table WHERE TIME < last_TIME ORDER BY TIME DESC LIMIT 10.
" Q! G& k! B! j
/ Q. N0 W7 C" n2 k( C8 C6 w. zSELECT * FROM table inner JOIN (SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t USING(id)
, g2 w2 Q4 }( c8 J3 n% b  C9 ^+ k
7 Q( V5 W2 o4 f% i' e* R

该用户从未签到

2#
发表于 2021-9-8 13:45 | 只看该作者
不同类型的索引有着不同的数据结构和功能

该用户从未签到

3#
发表于 2021-9-8 13:58 | 只看该作者
要优先选择符合存储需要的最小的数据类型

该用户从未签到

4#
发表于 2021-9-8 14:10 | 只看该作者
学习了  感谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-9-11 02:18 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表