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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
一.  基础规范
1 u8 H  H) V; d: }所有表都需要添加注释5 Q. l9 |7 `) Y
使用comment从句添加表和列的备注,从一开始就做好数据字典维护。7 j, Q8 a1 `/ ^6 n1 R# A  d
: I6 r5 F7 j) L6 {- w* O8 p) V
单表数据量建议控制在500万以内- V6 Q# M, s  c* E7 f" S
过大会给备份和恢复带来困难,可用历史数据归档(用于日志数据),分库分表(用于业务数据)等手段来控制数据量大小。8 R: ~/ ]8 V. n3 L3 M, r2 V
1 a1 ~* |6 B' v7 D2 r, y. N
不在数据库中存储图、文件等二进制数据5 A, [8 U% I, n
图或文件IO操作耗时,通常存储于文件服务器,数据库只存储文件地址信息。
0 C6 n  Z4 b; ^7 ?( }8 \
% N, t! c. O* Q0 [尽量冷热数据分离,减小表的宽度
6 ^- G; @6 y" y7 f把不常用且占宽大的字段从热表中分离可独立存储,每一行数据大小不超过65535字节。
  J  F5 r. w; x7 D8 \7 g# F0 Y, M
禁止测试、开发环境直连线上数据库
! J2 z3 y, C, O9 M
. b  H  f# S. b( T$ t二、命名规范
/ ~% v: y) t( G( V$ ?3 ~5 I! c  Z; ]" u" o: G, R* `
库名、表名、字段名必须使用小写字母,并采用下划线分割
+ O7 B+ U. O8 ?MySQL配置参数lower_case_table_names=1,即库表名以小写存储,大小写不敏感。如果是0,则库表名以实际情况存储,大小写敏感;如果是2,以实际情况存储,但以小写比较。如果大小写混合使用,可能存在abc,Abc,ABC等多个表共存,容易导致混乱。: e: J- B" l9 H, Y* @

6 K  E% K7 H4 A3 r* k库名、表名、字段名不要超过32个字符,需见名知意易于辨识! P. G7 m. |; [  v
库名、表名、字段名支持最多64个字符,但为了减少传输量,禁止超过32个字符。
$ z: ^2 R) \5 u+ `
- y% r  L) g6 Y3 u库名、表名、字段名禁止使用MySQL保留字2 X1 V, G; W2 d& C. C+ ?: c& V
当库名、表名、字段名等含有保留字时,SQL语句必须用反引号引用属性名称,这将使SQL语句书写、SHELL脚本中变量的转义变得非常复杂。
6 h0 E" B5 l6 _9 L; e: B; n( d* y& G* X3 @* v- [& ?
备份库、表必须以bak为前缀,并以日期为后缀
( Y# P( R7 L: d7 B/ s形如:bak_user_account_201903132 d  a: Z7 _! K7 L
" |8 N5 {9 [! l, [; }8 ~; e/ P
索引的命名0 c* R) h' b" G8 q( g8 R
主键索引名为 pk_字段名;唯一索引名为 uk _字段名;普通索引名则为 idx_字段名。
7 v5 b" l: z6 e$ r6 O/ z  e/ U. @2 [* \6 m

. z$ i2 M9 O  P三、字段设计规范
1 j. @9 W5 `% _
: X3 u% _9 K; o% L优先选择符合存储需要的最小的数据类型& h) e2 d$ d/ p; r7 B
列的字段类型越大,建立索引占据的空间就越大,使得一个页中的索引越少,IO次数增加,影响性能,能用int的就不用char或者varchar,能用tinyint的就不用int。状态status、类型type等字段推荐使用tinytint或者smallint类型节省存储空间;使用 UNSIGNED 存储非负数值;使用tinyint来代替 enum和boolean;存储 ip 最好用 int存储而非 char(15)。9 {+ S5 B/ }3 z/ q9 Q2 V) y

1 i; V: B+ v' y3 i不推荐使用blob,text等类型' i$ L0 |2 _0 L( ?( K
blob,text是为了存储极大的字符串而设计的数据类型,采用二进制与字符串方式存储,该数据类型不能设置默认值、不便于排序、不便于建立索引,varchar的性能会比text高很多,如果非要使用,建议将这种数据分离到单独的拓展表中。
7 i) [4 T! o3 _' r# m, A# ]) C. B1 I$ P
禁止使用字符串来存储日期型数据- V' Z* O- b! i4 u
一是无法使用日期函数计算比较,二是因为字符串存储要占更多的内存空间,datetime占8字节,timestamp是以int存储,占4字节。4 a; }, N) u$ I: S) p3 A  N- p: I

9 O, }& d  o. _2 z% o4 C, `1 h用DECIMAL代替FLOAT和DOUBLE存储精确浮点数+ f+ x9 t9 p/ y7 h  H; N
Decimal类型为精准浮点数,float 和 double 都有精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
& R9 e. z8 _3 l
/ }. u) w' `7 d) Y必须把字段定义为NOT NULL并设默认值# y# w  C, G: h6 {, I0 [! W
一是NULL需要更多的存储空间,二是NULL的列可能索引实效,三是NULL只能采用IS NULL或者IS NOT NULL,而在=/!=/in/not in时有大坑。1 V4 b: y' R& m- x) t: t

2 r% t" ]- H. s9 b) J- t' C使用varchar(20)存储手机号,不要使用整数
' P% U0 \4 h; q  W# t- y  J一是牵扯到国家代号,可能出现+/-/()等字符,例如+86,二是varchar可以模糊查询,例如like ‘138%’
  l+ E- y+ f9 D5 |
# [( A! V; N$ m- `, J% [根据业务区分使用char/varchar
- o9 ^9 S& L! h  Z& I字段长度固定,或者长度近似的业务场景,适合使用char,能够减少碎片,查询性能高2 F1 [, e! y/ R4 D( w

3 D0 i; V( i9 y& X+ p% I字段长度相差较大,或者更新较少的业务场景,适合使用varchar。
) \* K; h) u  u* i- @
; l3 c! A$ v4 H. i- [  C禁止在数据库中存储明文密码,把密码加密后存储) X7 s# \2 P2 o9 R  K
尽量不使用外键. ^  X' g8 ]) L5 i
建议在应用层实现外键的逻辑, 外键与级联更新不适合高并发场景,降低插入性能,大并发下容易产生死锁。
3 j. C" ^5 M8 m  G8 U4 [0 l2 W
8 T# L6 f9 p0 c  h) ~核心表必须有行数据的创建时间和最后更新时间) D8 z0 F% R1 F
核心表(如用户表,金钱相关的表)必须有行数据的创建时间字段create_time和最后更新时间字段update_time,便于查问题。
6 l) O# @6 h7 Q  S4 j; d- d4 T  _7 x7 [3 E

+ ~) w0 L! L; ?# c( c) `四、索引设计规范4 c7 [: \$ E' L- J

  Y; n+ M6 o4 k7 J, rMySQL的查询速度依赖良好的索引设计,因此索引对于高性能至关重要,合理的索引会加快查询速度,不合理的索引会降低速度。6 P1 l6 x: m  s5 l; g/ a5 G7 M1 j

# A% g$ m' W& q$ M; G& m索引其实就是一种数据结构(哈希表、树等),不同类型的索引有着不同的数据结构和功能。% e9 e  x( P( m2 r  S

9 M2 t- U* H& @7 x. U) z索引的作用是加速查询速度,维护数据的约束性(完整性、一致性)。对于加速查询,使用索引不一定是最好的选择,小表就直接全表扫描,中到大表就建索引,超大表就分区分表,要做好索引带来的好处和维护索引的成本之间的权衡。8 C6 X% ^( ~# \% u5 T  i! g. g
3 v8 \+ z. K# S4 I5 M6 A
单表的索引数建议不超过 5 个,单个索引中的字段数建议不超过 5 个& y5 C3 S+ _7 a: Y9 ~+ f$ j# L) O1 X
太多就起不到过滤作用了,索引也占空间,管理也耗资源。
- T3 d0 ~( r  _0 O) J% S4 h% Y( f4 s7 o$ K6 {; v) C0 r
对字符串使用前缀索引,前缀索引长度不超过8个字符) J+ `. `9 P7 D  ~1 U
不要索引blob/text等字段,不要索引大型字段,这样做会让索引占用太多的存储空间。( C7 {% o/ N6 Q) ~+ G+ u1 r# i

0 L( G  X, h/ m8 ?. S+ @前缀索引就是对文本的前几个字符建立索引,前缀索引能有效减小索引文件的大小,提高索引的速度。但是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用作覆盖索引(Covering Index); p$ w* o/ G/ N. _0 u
) j# s$ H2 b. a5 {) z& W
重要的SQL必须被索引,核心SQL优先考虑覆盖索引- @' l+ i  k/ z/ u
UPDATE、DELETE 语句的 WHERE 条件列;ORDER BY、GROUP BY、DISTINCT 的字段;多表 JOIN 的字段。覆盖索引可以避免Innodb表进行索引的二次查询,把随机IO变成顺序IO,加快查询效率。- n+ D9 D9 L+ i. |

4 R  m( m4 s& a/ \$ J  F联合索引区分度最大的字段放在前面
/ d4 O1 I- h% Y/ B; {选择筛选性更优的字段放在最前面,比如userid,carid等,type,status等筛选性一般不建议放在最前面。索引根据左前缀原则,当建立一个联合索引(a,b,c),则查询条件里面只有包含(a)或(a,b)或(a,b,c)的时候才能走索引,(a,c)作为条件的时候只能使用到a列索引,所以这个时候要确定a的返回列一定不能太多,不然语句设计就不合理,(b,c)则不能走索引。
- S6 \- o9 [; M) I+ g. h5 \" C( Y8 m3 n7 K
业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引5 b  S' l3 n0 e8 v) ]6 d6 p3 a7 ?
不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明
* l3 A2 \0 h3 m3 x2 X  Y7 r' a4 \! t8 A
显的; 另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。2 J* i* N; s1 z# N6 p$ J' R* N" I
& Z, F2 o; @% g6 V+ O8 K1 o
InnoDB 和 MyISAM 存储引擎表,索引类型必须为BTREE
* G) {: l; T* C) [4 AMEMORY表可以根据需要选择 HASH 或者 BTREE 类型索引。
8 _! M! t- B9 \# U& C1 g; J- t; t! l  E. x& r3 u1 ]' I2 T
MYSQL 中索引的限制6 ^) I+ k4 Y( C
MYISAM 存储引擎索引长度的总和不能超过 1000 字节
* n1 `2 k0 q" y, h: q& L& {& W
! x  t8 [  [% f  aBLOB 和 TEXT 类型的列只能创建前缀索引: w5 k. l* ]; {! P, u* t0 I6 c/ _. t

0 t* ^! [' ^: P使用不等于 (!= 或者 <>) 的时候, MYSQL 无法使用索引
& ~: p  {; r+ V  Q
6 o  g/ q1 i" U1 N3 J过滤字段使用函数运算 (如 abs (column)) 后, MYSQL无法使用索引/ ], `( g9 M! Q5 l6 \# g5 I
! w/ D: F: r! D  V- r. U3 S
join语句中join条件字段类型不一致的时候MYSQL无法使用索引" A7 t8 L" D( g. m1 R% l

" K* E" M  e& b. B3 h( t  {使用 LIKE 操作的时候如果条件以通配符开始 (如 ‘%abc…’)时, MYSQL无法使用索引/ ~# v. Z% i2 |& L
; I# L" m+ p+ ?  o, w8 q
使用非等值查询的时候, MYSQL无法使用 Hash 索引。
% V" ^" X  X3 `4 X' Z. t, @! O6 }- v  y7 O' k! F2 F- R

# [' |7 B5 O4 a+ Y2 S; i五、SQL查询规范
% N/ n9 r. b2 ?! s4 q7 [/ H5 X. h+ h; R) l& O3 r
按需索取拒绝 select *
: Q( c4 y$ n7 g0 ]无法索引覆盖,回表操作,IO增加;额外的内存负担,大量冷数据灌入innodb_buffer_pool_size,降低查询命中率;额外的网络传输开销。* I- J" K5 Q: N: @' `, ~( q
; F7 F3 b' \- L, E8 b# q- g- c
超过三个表禁止 join
9 q) \/ E4 F$ y7 k2 s  x需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段有索引。
/ N, _- `) S+ ?  y& ^* P; H- n: m8 v; b- Q( g* H
涉及到复杂sql时,须用explain检验索引设计% s0 J  `* x# K3 O# z, ^9 y0 {# D
对应同一列进行 or 判断时,使用 in 代替 or  v* t0 q" H) w* r
in 的值不要超过 500 个, in 操作可以更有效的利用索引,or 大多数情况下很少能利用到索引。
! M: k6 @$ {) C% U. m6 k$ x* k6 p" o% B  _# F
in 操作能避免则避免
) M5 o. Q' U1 g* I' d若实在避免不了,需要仔细评估 in 后边的集合元素数量,控制在 1000 个之内。
/ d& o  I0 T( s: ?
$ j; v1 h  f# UWHERE从句中禁止对列进行函数转换和计算* A. q. H: y8 m2 `) J2 b/ \& \3 P+ B/ {
对列进行函数转换或计算时会导致无法使用索引。% t6 n$ ~' B! |  d

! [# G$ B* b- Z# O) L5 Vcount(列名)或 count(常量) 替代不了 count(*)
, [& F; N8 v8 A. ~7 D1 u; Ncount(*)是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无,! d! C9 c; A0 Z4 J8 d6 G2 H' p

: i: T6 c! T' z/ V+ Scount(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
, {, A9 Q% o- C: C6 S: n! s8 S0 k" E5 l6 B1 t
不要使用UNION,推荐使用UNION ALL1 i- ]; X) y3 [# ?% }. n
因为union all不需要去重,节省数据库资源,提高性能,另外子句个数限制在5个以内。1 \2 h4 `" L) C4 l
! s* [# o4 `6 l% Y
禁止使用 order by rand() 进行随机排序
: X: o; x5 D2 S4 y会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的 CPU 和 IO 及内存资源,推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。
5 W! x, y6 p1 A. N% m" r. m1 p7 B' f' F9 P% h) j
不得使用外键与级联,一切外键概念必须在应用层解决) L# ]3 d% Q0 S9 ^! D' i- \
以学生和成绩的关系为例,学生表中的 student_id是主键,那么成绩表中的 student_id则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新, 即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群; 级联更新是强阻塞,存在数据库更新风暴的风险;而且外键影响数据库的插入速度。
+ _3 _" H) u( {# {' D% Z' @: u( C% V
" t2 Y9 Q  q/ G0 F  O* N" E使用合理的分页方式以提高分页效率7 S$ f( e8 @, ^; v" I9 H! V8 B
不推荐 SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;
) Q( k) z' r! I+ D; o. P- Z  ~: r. P7 p. C5 p+ \8 n- U! z
原因:会导致大量的io,因为MySQL使用的是提前读取策略! L' b" G0 R. `6 g! h
4 z" f. J% Z1 g0 v% e1 Y+ h
推荐:SELECT * FROM table WHERE TIME < last_TIME ORDER BY TIME DESC LIMIT 10.5 F* }0 C# s- h$ d. O  }

1 \2 c  y1 d6 v5 cSELECT * FROM table inner JOIN (SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t USING(id)9 U) A) P- a8 \, l1 J7 u
: }9 ]1 t- c0 F1 {5 i2 p
8 v5 f5 `) @; `  H0 l% }8 \

该用户从未签到

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-8-21 07:11 , Processed in 0.109375 second(s), 23 queries , Gzip On.

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

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

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