站长社区 _ SEO论坛 _ SEO优化

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 57|回复: 0
收起左侧

[Mysql] 应用开发实践之关系型数据库(以MySql为例)小结

[复制链接]
gydtep2002 发表于 2020-5-6 16:31:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

x
本文主要是对目前工作中使用到的DB相关知识点的总结,应用开发了解到以下深度基本足以应对日常需求,再深入下去更偏向于DB本身的理论、调优和运维实践。' U' E- Q8 H) Z! Z4 ]2 }
不在本文重点关注讨论的内容(可能会提到一些):
具体的DQL、DML、DDL、DCL等语法
6 P- F% c" J3 }( a基础性的概念,如主键、索引、存储过程(注:阿里巴巴规范中禁止使用存储过程)等( b& Z$ j' Z* V6 G1 |7 g6 H
联合查询,我个人不太喜欢在应用中写过于复杂的SQL,性能和后续维护容易出现问题
  T& g; z/ V1 J' x6 u6 x可能会用到的具体DB特性,如oracle的DATA GUARD: ^% Z% h/ Q1 O9 ^5 x9 G
有一些属于基础知识或语法但是常用的信息,也会列一下,如join的用法。
申请阿里云服务器等产品时,可以使用2000元阿里云代金券,阿里云官网领取网址:https://dashi.aliyun.com/site/yun/youhui6 @2 y; }$ b5 L1 i0 }2 k& L4 w3 B
一、基础
  • ACID
    6 J# H: N7 m2 i7 c8 t7 uDB的四大特性,这里简单概括下不具体展开。

    4 i! i) v' I' `  F
原子性(Atomicity):事务操作中的多条SQL,要么全部成功要么全部失败,失败后回滚不对原有数据造成任何影响。
2 ~$ S# V5 V8 R一致性(Consistency):事务开始前和结束后,数据库的完整性没有被破坏。如触发器、约束、级联回滚
4 c9 A% g: X) Y/ ]% M" B隔离性(Isolation):多个事务支持并发读写。具体隔离级别见后文。- U, |- Y0 N; X( d. }
持久性(Durability):事务结束后,修改是永久的,不丢失。
  • 范式
    . G9 g, O( `5 `& _3 ]这里展开讲比较复杂,实践中很少用到,一般满足1NF即可。

    ' r# i7 z- S' s& K6 q# m+ A
高一级必满足低一级。
1NF:每个属性都不可再分,即表的列是最原子的
9 w" y. X9 ]5 u1 T6 ]6 |2NF:在1NF基础上,消除非主属性对键的部分依赖。这里不解释非主属性和键的含义,可以简单认为是指不存在列A可以通过列B来获取,如“学生姓名-学号”这种y=f(x)的函数关系。
5 i( L- z+ D0 P) `, L1 P3NF:在2NF的基础之上,消除了非主属性对于码的传递函数依赖) l$ u5 o, z+ C& E5 L' w
BCNF:对于关系模式R,如果每一个函数依赖的决定因素都包含键,则R属于BCNF范式* e/ }  W3 p( I$ M5 V
有兴趣可以参考:范式通俗理解:1NF、2NF、3NF和BNCF
4 I/ l; K, y' _1 I二、事务
  • 事务的隔离级别, E) k2 P8 w  T1 n4 i5 L
    3.1 读现象
    6 J: ^( V$ k2 a9 e7 i8 L
读现象是伴生于不同的隔离级别出现的。读现象的场景都是在多个事务并发执行的前提下可能出现的:
脏读 —— 一个事务读取了另一个未提交事务执行过程中的数据。此时另一个事务可能会由于提交失败而回滚。$ i. l; k& |7 s: ~2 ]- z
不可重复读 —— 一个事务执行过程中多次查询同一条数据但返回了不同查询结果。这说明在事务执行过程中,数据被其他事务修改并提交了。
  X! ]* w* K/ g幻读 —— 事务1先行查询了某种数据,在修改或插入提交之前,事务2对此类数据进行了插入或删除并提交,导致了事务1对预期结果的数量变化。
0 V% G$ K* I5 D; v3.2 隔离级别2 G8 ?3 n1 K  I
未提交读(read uncommited):允许另外一个事务可以看到这个事务未提交的数据。
6 q7 y6 A, Q" p1 F提交读(read commited):保证一个事务提交后才能被另外一个事务读取,而不能读取未提交的数据。- W* ?$ ]3 _" j1 f: v3 Q
可重复读(repeatable read):保持读锁和写锁一直到事务提交,但不提供范围锁,因此不能避免幻读。8 @" R+ ]2 }/ m4 {; T0 ~: h
可序列化(serializable):代价最高但最可靠的事务隔离级别,事务被处理为顺序执行。" U9 T  g# ^' q7 z) O" L
3.3 隔离级别与读现象
( W  ]8 w9 V) ^% s7 L9 W: ~2 G不同的隔离级别可以防止读现象。
隔离级别 脏读 不可重复读 幻影读
# Z+ E$ h$ t' B未提交读 可能发生 可能发生 可能发生0 }' Y7 ]+ X% i0 B" @
提交读 - 可能发生 可能发生) A% A8 M7 j7 v+ l
可重复读 - - 可能发生
! h* k5 }, _1 a: l/ E可序列化 - - -5 E5 v0 s- [  |6 k( _
注:为什么提交读不能避免不可重复读?假设A事务需要读取两次变量a,第一次读取时a=10,执行过程中a被事务B修改变成了20,那么A第二次读时a与第一次的结果不同。
3.4 查看DB的隔离级别
6 `* k& Q4 F. N. h// 查看当前会话
* o+ g& m  E6 k+ u& i1 B7 Gselect @@tx_isolation;
8 S/ m% b* Y( S  i; X2 ]) e// 查看当前系统: C* a8 U4 h8 [# J! a
select @@global.tx_isolation;
3 w! B) U' ?, x3 TMySql 5.7.14-ALISQL版默认是提交读。
  • 事务传播性(Spring)
    7 Z9 j( h$ W5 g+ f5 l6 i在多个含有事务方法的相互调用时,事务如何在这些方法间传播。

    + p% t2 F& \) A
spring支持7种事务传播行为:
propagation_requierd:如果当前没有事务,就新建一个事务;否则加入到这个已有事务中,这是最常见的选择。* w% X6 D" V1 ^
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。6 p0 B( b" l% B: _% X' a
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- o9 {2 p1 f6 h6 s2 n: M, E( @0 ppropagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。& ~# k& Z' I3 i; F2 X% Q6 A  f
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
/ C1 C- |( w! ?( W! \propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
" C: [$ Y9 x) q- C/ f0 npropagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作8 |- Y$ k% \; R2 t" G7 Z
Spring默认是propagation_requierd。9 a7 `6 N. ]# }. z
为了便于理解,将以上几种传播行为分类:
传播性的类型 当前不在事务中 当前在事务中 备注
$ d  s0 Y, e! C) _2 L5 m: `; Spropagation_requierd 新建一个事务 加入到当前事务 最常见的选择: d- ?; Q# Y- [  o  k2 e6 s1 r8 F
propagation_supports 非事务执行 加入当前事务
' Y# A3 [# b# f" o. y: ], ypropagation_mandatory 抛异常 加入当前事务
- z4 u& G- t7 u5 i  h$ v5 I; Z. Jpropagation_required_new 新建事务 挂起当前事务" W" Y6 x: K3 a5 W2 s
propagation_not_supported 非事务执行 挂起当前事务
9 B- d5 Z8 R' b+ w) ^propagation_never 非事务执行 抛异常
. |( ?: Q8 g* z% upropagation_nested 新建事务 嵌套事务内执行
, m7 e8 a% e2 p' u5 w! U7 A* w事务挂起( m6 f9 `' w1 @5 J2 z' ?
指当前方法不再受所属的事务控制直到该方法结束。比如A方法起了一个事务,调用B方法时B挂起事务,那么B的所有DB操作都不再受A方法的事务控制,直到B执行结束。
事务嵌套
; Y4 l4 j7 z- G( T0 d2 A嵌套的事务可以独立于当前事务提交或回滚。
三、性能与优化
  • 执行计划
    % W+ r  |; p5 ~, R' a确认SQL在实际执行时的执行情况,如是否走上索引、走了哪个索引、扫描行数、执行顺序(如多个select级联查询)
    3 T1 a: [: n8 N+ V0 X/ H- C0 ~- n: `
查看方式
# a& W0 l  o( ~: }% Zexplain XXX
) b& H$ f+ ?& L  x6 h1 `6 n解读
6 d* L# \7 e) g% O  TMySql: MySQL_执行计划详细说明
  • 索引相关
    ; N# E4 C" W5 a6.1 聚集/非聚集索引
    ' ?" n0 @4 V* @( }) a
聚集索引:逻辑上和物理上都是连续的,如主键,一般一个表只有一个聚集索引; }2 P5 h7 t/ A) {% d. K( ]
非聚集索引:逻辑上是连续的但物理上不是" D" R" R+ |# v6 t" p8 W0 w
以Mysql的InnoDB为例:, |: c7 ~+ O5 o1 R' E( J
主键是聚集索引。! _5 C; t. Q7 u5 t0 b; V2 m( ?
唯一索引、普通索引、前缀索引等都是二级索引(辅助索引)。
结合B+树的知识,对于聚集索引,索引数据和存储数据是在一起的,比如id-age这个记录。
3 r8 f$ u' B; ~' h' d对于非聚集索引,只有索引数据,定位具体的记录需要通过索引来找,也即通过索引找到id,再通过id找到id-age这条记录。
6.2 覆盖索引
3 z; v+ I4 _: L' c4 z9 o: P1 u查询条件和结果全部在一个索引中,MySql不需要通过二级索引查到主键后再查一遍数据就可以返回查询数据。覆盖索引可以大大提升查询效率,举例
select a, b from table_x where c = XXX order by d;4 J8 D7 B) ~! f
其中a、b、c、d全部在索引中,那么这就是覆盖索引。
对于做不到覆盖索引的查询,查到主键后还要回到数据表中把数据查询出来,则称为__回表__。
6.3 索引有序性2 z/ b  d: f% I$ t' |: |- D: e
对于联合索引,建立(a, b, c)相当于建立(a), (a,b), (a,b,c)。* d1 U; s$ T4 E- {( a# V
在这个索引下,遵循”最左前缀原理“,即先按a排序,再按b排序,最后按c排序。
7 A9 X) e' `$ {1 S' k9 V' \如果缺失了前一列,如where b = xxx,则走不上索引。
) Y( S( o( o+ l( s/ O如果某一列不是等值匹配,如where a>10 and b = 1,则只能部分走上索引,b走不上索引。非等值匹配有<、>、!=、IN、LIKE等。
更完整的可以参考mysql组合索引的有序性
6.4 创建了索引但没有走上的原因
5 y: L" A) a- J# t: Q8 S) c) y1 Z使用了<、>、!=、IN、LIKE等(非最左的like,也即like 'xxx%'是可以的)8 s- {7 }4 [1 o& P
使用or连接查询子句0 z. L, @+ E$ Z7 R
预期使用联合索引,但实际上没有按照最左前缀原理排序(见上文7.3节)
/ Y& H$ g& p  V9 v9 l9 }字符串类型没有使用引号
: `1 A$ N: Y; ?) m3 M全表扫描比走索引快
! g) W% b. ?1 ~& M5 l+ g5 a$ s0 ~where子句中包含了函数或表达式* G1 P) s4 Y, P0 ?: Q: _7 Z7 l) S
为什么你创建的数据库索引没有生效,索引失效的条件!
  • 行锁和表锁
    8 R/ E$ ~0 p. d8 ^8 g9 G) Fselect...for update,走上索引(含主键)是行锁,没走上就是表锁。但是如果索引匹配过多,也会变成表锁。

    ( w, {4 b/ T# S! v
[转载&整理&链接]mysql 通过测试'for update',深入了解行锁、表锁、索引
简单概括一下:
! ~, M; v" B0 I* z9 Y5 VB树的中间节点和叶子节点都有不止一个关键字(key)。B树出现的目的是减少磁盘臂移动的开销从而,尽量减少读写的次数。4 S1 I; w  o5 T- |+ k% {
B+树与B树的不同在于,B+树的数据都在叶子节点上,中间件节点没有数据。- ^3 U$ P- d0 F7 J% V
应用:由于B树最左前缀匹配的特性,如果用左模糊查询(like "%xxx")是走不上索引的。
四、应用开发
  • 分页查询
    7 e- b( b8 @4 v5 v" @: x查询第N页(下标从1开始)数据,每页大小PageSize

    * C6 G: G4 c& d# Q
// 先获取符合条件的总数/ m+ p$ @6 A& s; h
select count(1) from tableA where XXX& I9 p# e0 F; g4 P$ z" w' W
// 查询该页
4 @# ]8 t! I# g# D5 o# b# B% Z// 偏移量,可选 offset = (pageSize-1) * N
; b- M$ ?+ y; x1 O0 L4 V// 行数 rows = pageSize; `2 X! [$ e3 @# m
select row1, ..., rowN from tableA where XXX limit offset, rows
  • Join8 P+ P$ V8 i2 ^( ?8 V
    10.1 语法

    : e- m& D8 N, H; Y1 Q7 j0 c
SELECT Table1.Row1, Table1.Row2, Table2.Row1
" ~2 P  `' i2 l" h8 T; R. IFROM Table1
7 e3 s7 |) m1 ^( x4 H! cINNER JOIN Table20 m% G& C8 ?2 C* g
ON Table1.Row2 = Table2.Row2/ n: b/ Y" M: |7 s# X7 A
ORDER BY Table1.Row1
5 v) M4 W$ D) A. w6 Y% S$ W0 h9 i! Z10.2 种类" F+ Q9 a$ Z5 B: {" e- J
inner join( = join),都匹配才返回* j& T9 K* G' |# Z
left join,左表全返回不管右表有没有匹配
: r, T- K8 H& O$ P: }7 gright join,右表全返回不管左表有没有匹配
- r% M2 s/ ^4 @0 U+ [full join,全返回,左表右表无论对方匹配都返回所有行
  • MyBatis缓存
    , b- w( ~8 |0 n- CMyBatis缓存分为两级:一级缓存,SqlSession级别;二级缓存,SqlSessionFactory级别。和通常命名习惯相反,二级缓存的作用范围大于一级缓存,原因是,SqlSession是由SqlSessionFactory创建的。
    / K- o% J: c3 \# E
MyBatis默认开启一级缓存,不开启二级缓存。一级缓存生效于同一个SqlSession,当这个session没有做任何update操作且查询完全相同时,会返回一样的数据。/ S2 C7 E5 ~$ j) I; L4 G+ l
此时,在并发环境下,很有可能会发生这种情况:在一台服务器A上连续查询两次,两次属于同一个SqlSession;中间另一个服务器B对表做了更新,A看到的第二次查询结果仍然是旧的。
关于缓存的细节,如如何判断“同一次查询”、缓存有效期、SqlSession原理,可以自行查阅。推荐mybatis中文官网,有很多原理的介绍。
. k$ T6 }. X0 ~; k0 v; L1 ^在实践中,spring和mybatis整合以后每次查询都会刷新sqlSession,即一级缓存是无效的。: `2 F& [4 }) r9 q% a4 O
MyBatis缓存系列- }1 L: l' E' S
单独提一下,二级缓存的readOnly默认为false,同一条数据在内存中每个对象都是独立的,可修改相互不影响。可参考如何理解Mybatis二级缓存配置中的readOnly?
  • mybatis和hibernate
    & V4 p' W: X/ N我在工作中绝大多数时间都用mybatis+spring/springboot写持久层,只有一个应用因为使用SpringDataJPA才对hibernate才做了一些了解。

    8 _8 C6 J- U% d6 L( k' A6 H
看了一些资料,了解到二者在写法以外,性能的差别主要在于多表查询这个场景,hibernate会比mybatis慢一些,原因是
hibernate为了保证POJO的数据完整性,需要将关联的数据加载,需要额外地查询更多的数据。
MyBatis和Hibernate相比,优势在哪里? - 郑沐兴的回答 - 知乎
" s( R$ c: `0 g, R此外,JPA如果想运行原生sql,可以使用EntityManager。
  • 水平扩展与垂直扩展, M$ A/ ^3 b& L5 r
    13.1 水平扩展——分库分表一般思路

    8 A4 p# V$ h# i# A6 q
按某一字段将一张表分片,如userId。分片方式:' |# D& V2 h0 o! `/ m: m
第X位到Y位的值* S" b7 S7 q$ N7 ?  F  ^
字段hash值* `! V5 o; N# H* l; o* \
特殊值特殊处理,如某KA(Key Account关键客户)数据量较大,单独一个分表1 M5 h6 t' O6 ^; `7 x4 D( x
13.2 水平扩展——历史库) d* g/ H; x0 ?+ i
按日期定时同步迁移及清理线上数据- \. v0 ]6 N2 R. l8 U6 L# M# X
查询需要根据日期路由到线上库或历史库
13.3 水平扩展——按业务拆表
4 l4 ?2 C4 F: C  Y" s0 F6 F, L按业务,已处理数据及未处理数据拆分。如已受理未申请单和已完结申请单分开保存。
13.4 垂直扩展$ D* ~+ a. o( p) q) F
提供更多、更强、容量更大的硬件资源。
13.5 FailOver
+ T, i( l$ G$ i; Z- W! @7 z/ U3 m% }在计算机术语中,故障转移(英语:failover),即当活动的服务或应用意外终止时,快速启用冗余或备用的服务器、系统、硬件或者网络接替它们工作。 故障转移(failover)与交换转移操作基本相同,只是故障转移通常是自动完成的,没有警告提醒手动完成,而交换转移需要手动进行。 ——wiki
FailOver是从应用层面做的,不是单纯DB层面。
13.5.1 背景; n, j* z- _' w6 S
单库架构,一旦库挂掉整个服务不可用;
; }  z$ H7 J3 P2 Y& a主备架构,切换时有时间延迟;
( E+ s" }* V4 G7 T& BFailOver从分布上来看仍然是主备架构,但是增加了系统自动切换恢复能力。
13.5.2 思想
4 _% M$ u  {- \" @9 W9 [. Y' M和去IOE是一致的,用大量相对廉价的硬件,拆分服务,减少单点,提升整体的可用性。
13.5.3 交互模式+ z& ]- s* B8 n) r( f% F
仅举两个最典型的例子,具体场景需要结合硬件能力和应用架构综合分析。
13.5.3.1 记账型  S+ G0 ^0 N* X9 Z- P
特点:
主备准实时同步,Failover库平时不做读写
0 F5 i/ R: [" Q, M2 [. V6 v主备库表结构一致,Failover库不一定和主备库的表一致(可能会少一些不需要用到的表)5 I! U& F. U4 J! @$ m
账户型数据保持最终一致性即可
1 F- X) Y% Z6 T# W: s方案:
按比列拆表拆库,降低单个库挂掉时影响用户数# B, S6 `1 E2 U& ^5 j( c4 S
正常工作时,主备准实时同步,Failover库不读写, j/ @1 T) G0 r9 G: M' J* u) h: c
主库发生异常时,切换到备库读,Failover库记录操作信息。同时,业务操作尽量分流到不依赖相关库到支路上。$ {1 Q0 D4 o6 D
主库恢复时,不再写入Failover,将Failover库和主库内容做merge,回写主库,主库再同步备库
( B/ @7 t+ ]* Q4 R注:可以采取双写、基于读库(上文中所述,利用oracle的data guard、mysql的replication等)、异步消息等保证主备一致。
13.5.3.2 交易流水型
( `! _; x) F; x7 S+ `+ A. _( x特点:
数据保证创建,不保证推进。即交易下单失败,重新下单
5 ~3 O' }; C3 m/ vfailover库交易号与主库通过某些位隔离,不重复0 c+ f$ O4 M: p' r3 C* R" i
方案:
和“记账型”类似,Failover库数据推进业务完成即可- w6 \& e5 i' Z' w+ @; }
可以不回写failover期间的数据,依赖中间件读failover库中数据
) z/ C; g4 U% b4 p7 C13.6 读写分离$ ~% p7 n: F$ o
为了解决读大于多于写的场景下数据库瓶颈的一种架构模式。同样需要结合具体业务不能生搬硬套。
. l7 f( ~( G0 ]' b- Q主要是一写多读的架构,在主库挂掉的场景下有可能需要考虑使用paxos算法来决定新的主库。
$ D$ F4 x' n; ]) E: _1 y7 _在做读写分离前,可以先考虑缓存是否能解决当前场景的问题。
五、运维
  • binlog0 K1 m& Y- n2 E% @6 p5 j9 O' g
    记录DB操作(不含查询)及其他执行信息的二进制日志。
    5 c( s% p7 T/ C, v6 W# ~* p& j
可以参考下面两篇文章简单了解下。
* q+ X. ~/ a3 _. y( p( I0 K( l1 t【原创】研发应该懂的binlog知识(上); r- N& c: ]$ t; c  o3 T, {
【原创】研发应该懂的binlog知识(下)
六、其他话题
  • 零碎的话题0 Z0 }9 Q( c# \7 q8 b' O
    想起来就补一些。

    % G( a% Q9 Z9 E2 U- N# e# V
15.1 列的默认值
/ q) _- J* u' d. n! t3 r$ w: n$ F* i对于有默认值的非空列,如果在insert语句中指明了这一列且值为null,插入仍然会报错,此时不会取默认值。让该列取默认值的方式是,不让该列出现在insert语句中。
15.2 索引下推
+ v  z9 b$ V$ _. j0 C' M& DMySql5.6做的优化之一,可以在like查询中提高性能。利用查询子句中能确定的查询条件,减少一次查询匹配到的索引,从而减少回表查询的数据。
  • 延伸话题
    9 z9 c, N, m0 c4 p. I- b. f$ a可以自行研究的话题,限于笔者接触范围和篇幅,不展开来写。

    ) w, u8 X: F6 P$ C& _
索引建立实践,是否越多越好,应该怎么选择索引列
' |! {2 N+ a& c4 ?! _) _  I* Khibernate和mybaits的区别,最大区别是mybatis需要手写sql,用一定的工作量更大的灵活性,利于优化和多表联合查询
( A% G. |1 f6 @5 dredo log、undo log,与DB本身的分离) @9 t6 U0 i# h+ }) L: Z$ v( l
以下内容可能被滥用,我在实际工作中几乎没有用到,有兴趣可以自行了解。
- S+ O& {0 ?: r, {1 B/ K触发器+ t" f) l! g  d8 L
union" g" O; I. v  @; S3 q
视图& h9 z% T, `& n6 ?3 L0 U
全表扫描时发生的filesort原理
4 E6 F- f1 o; G+ l附:”点评“ 《阿里巴巴JAVA开发手册》之MySql规范部分
# ?: n: X4 p% v& e1 \/ I  R8 W开发中遵守一些事先约定好的规范,有助于提升研发效率(无论是个人还是团队内部或团队之间),避免犯一些重复错误,也有助于后续的维护。对于《阿里巴巴JAVA开发手册》中的规范,限于篇幅并没有写明原因,笔者基于自己的开发经验进行一些点评,供参考。8 X7 r" X. H6 ~3 }% \% Q
本来是想针对《阿里巴巴JAVA开发手册》MySql规范部分这一部分补一下点评的,但是发现前两天新出的泰山版已经补上很多说明,没必要一一点评,直接下载来看就好:https://files.cnblogs.com/files/wuyuegb2312/《Java开发手册(泰山版)》.pdf.zip
可以看出,前面一部分有很多规范都是和Java OOP相关联的。对于部分条目,是之前没注意到的,单独拉出来点评下。
count(*)和count(1)
- j( e; {  U; I% u) U7 A* a8 J9 ^【强制】不要使用 count(列名)或 count(常量)来替代 count(),count()是 SQL92 定义的标
& S: O" ]% Z3 A6 c( P% N4 X1 O准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
. S, {4 A+ ]. a7 h6 b说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
官方文档提到,InnoDB下count(*)和count(1)是没有区别的:
InnoDB handles SELECT COUNT() and SELECT COUNT(1) operations in the same way. There is no performance difference.0 x1 `+ [, {: c6 H5 x
但考虑到其他实现对count()有优化(如MyISAM,前提是没有WHERE和GROUP BY子句,直接取缓存的总数),再考虑到用其他DB的情况,统一起见一直用count(*)就好了。* E3 p- l" p5 s* B0 B0 x
更详细的分析可以看 为什么阿里巴巴禁止使用 count(列名)或 count(常量)来替代 count(*)
禁用外键
8 G: X9 v! ~! T9 p* O1 W8 f4 G【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
' V& c7 X; K: t. G+ E# p( M" W说明:(概念解释)学生表中的 student_id 是主键,那么成绩表中的student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
禁止使用外键,在本例中并不是不允许在成绩表中存放student_id字段,只是不设置成为外键即可,更新由应用层来做。
2 }3 q, ]! h3 L# t4 ~$ @6 O
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|易采站长站 ( 蒙ICP备14002389-1号 ) |

GMT+8, 2020-6-2 06:59

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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