数学建模社区-数学中国
标题:
拼多多面试问了数据库基础知识,今天分享出来
[打印本页]
作者:
杨利霞
时间:
2020-4-28 15:19
标题:
拼多多面试问了数据库基础知识,今天分享出来
拼多多面试问了数据库基础知识,今天分享出来
* T+ d2 G# ^& N( ?/ I; a$ |0 {0 Y
7 X7 ~, M. m. V$ `$ y
前言
! o* |6 G8 o/ W! I; o6 v' d
5 t2 X) F- [; {, B- o
我是个标题党,所有文章的名字只是我的噱头,我们应该有一颗谦逊的心,所以希望大家怀着空杯心态好好学,一起进步。
: w6 B$ b9 z" B$ f& ]' `$ @
. a! k0 Y# }8 V0 B
数据库我想大家应该一点都不陌生吧,我想不管你写啥的,数据库就算没用过也听过了,是我们项目体系里面不可或缺的一环。
" B. {& N+ n" ~
, u( k( {% D" w
问了一圈,身边朋友公司要么用自研,要么就清一色的MySQL,所以想看Oracle的朋友可能要失望了,但是不影响你了解数据库的通用知识。
! I V, @- h' R5 l
( f! b8 o" Y+ b" Q" Y6 f
正文
+ O) }. C. |9 h4 `- m6 a, v1 p
, [& J1 Z" s" p/ W @% D! P
你知道MySQL的基本架构么?你能在纸上给我大致画出这个示意图么?
2 J# o; Z n) }- w' B
2020-4-28 15:17 上传
下载附件
(48.19 KB)
0 m7 t# s x6 ]" n/ Z
好的那我们按照顺序了解下,连接器是啥?
$ |7 w( O \7 s! e* m8 G
我们要进行查询,第一步就是先去链接数据库,那这个时候就是连接器跟我们对接。
* S9 {6 v% @& D$ `1 D0 b+ B
% ]! w( f, g; F x# B
他负责跟客户端建立链接、获取权限、维持和管理连接。
5 }! X8 O( c0 V
- _3 l; z; I% a
链接的时候会经过TCP握手,然后身份验证,然后我们输入用户名密码就好了。
& C) q" O/ O |4 c
9 q6 \0 A4 [/ ^
验证ok后,我们就连上了这个MySQL服务了,但是这个时候我们处于空闲状态。
1 ~$ j+ i: t( ]* \. j% t: j
. f8 W$ ?; X4 d; c( w
怎么查看空闲连接列表?
2 w3 w# ?, C m# b
show processlist,下图就是我在自己的数据库表执行命令的结果,其中的Command列显示为Sleep的这一行,就表示现在系统里面有一个空闲连接。
3 l/ i' y6 }8 s+ ]
2020-4-28 15:18 上传
下载附件
(56.41 KB)
x) ^3 @# x( I: I3 U
这里需要注意的是,我们数据库的客户端太久没响应,连接器就会自动断开了,这个时间参数是wait_timeout控制住的,默认时长为8小时。
( b5 m+ O l r. C) Z( R
1 h) ]3 ?& h+ {+ j
断开后重连的时候会报错,如果你想再继续操作,你就需要重连了。
$ R3 n Y6 o9 }: z* w% S* Q1 \
. _. C* @' F6 l
这个有个我看过的书本的案例:
/ ^' ~# l& W% B( G
$ Z. s' A" x$ z2 [$ T1 \
一个在政府里的朋友说,他们的系统很奇怪,每天早上都得重启一下应用程序,否则就提示连接数据库失败,他们都不知道该怎么办。
+ A$ ]- C# t5 Y
我分析说,按照这个错误提示,应该就是连接时间过长了,断开了连接。数据库默认的超时时间是8小时,而你们平时六点下班,下班之后系统就没有人用了,等到第二天早上九点甚至十点才上班,这中间的时间已经超过10个小时了,数据库的连接肯定就会断开了。
4 g6 m/ v3 g; C7 ?( R0 m3 w5 @
是的,就是超出了超时时间,然后写代码的人也没注意到这个细节,所以才会出现这个问题。
0 w Y( m; \/ C! b2 Y6 i1 z7 F
0 u+ E4 l% k- r
把超时时间改得长一点,问题就解决了。
6 `9 p) R, `. j" d' v3 u
% F$ r, E6 s5 @
这种参数其实我们平时不一定能接触到,但是真的遇到问题的时候,知道每个参数的大概用法,不至于让你变成无头苍蝇。
# R0 y u2 ?8 x1 @7 U( G$ s
- J2 o* S* i8 w: P
那除了重新链接,还有别的方式么?因为建立链接还是比较麻烦的。
+ [: a$ U8 q' w* g1 w
使用长连接。
1 c" c9 n; Y0 L" ]; s3 a- X$ b& h
9 v: V/ v( R$ k: ]5 K+ A' u9 d6 `
但是这里有个缺点,使用长连接之后,内存会飙得很快,我们知道MySQL在执行过程中临时使用的内存是管理在连接对象里面的。
' Y9 m& Y% Y8 n( X5 c
! z& y$ d0 z8 c( L+ b, A
只有在链接断开的时候才能得到释放,那如果一直使用长连接,那就会导致OOM(Out Of Memory),会导致MySQL重启,在JVM里面就会导致频繁的Full GC。
: r1 v5 c% ]. D% N. k7 r2 U
% O# k7 K; Y6 d
那你会怎么解决?
& e; C' |2 v/ o# A4 ]; ?
我一般会定期断开长连接,使用一段时间后,或者程序里面判断执行过一个占用内存比较大的查询后就断开连接,需要的时候重连就好了。
8 p+ P% [0 K l2 {' N8 w
8 ^" @& w2 u+ C- r- z3 u
还有别的方法么?你这种感觉不优雅呀小老弟。
4 K; ]: [$ t5 W$ l5 q8 M) `1 i
执行比较大的一个查询后,执行mysql_reset_connection可以重新初始化连接资源。这个过程相比上面一种会好点,不需要重连,但是会初始化连接的状态。
& A9 o: s. ?% z" Y6 Y
$ c( q! U& w' D! p9 T' l/ ]$ i9 W- l
你了解MySQL的查询缓存么?
# x \9 N) Z6 f( Y
MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。
9 t% }9 G, D* E _6 b1 ~" G* j
8 E& Y- q0 ?8 G8 s1 K j
大家是不是好奇同一条语句在MySQL执行两次,第一次和后面的时间是不一样的,后者明显快一些,这就是因为缓存的存在。
6 @# a2 @. R% `
7 o6 N0 P+ Q% }/ ~; h
他跟Redis一样,只要是你之前执行过的语句,都会在内存里面用key-value形式存储着。
7 R0 p2 P+ O6 Y {* H' F
8 H5 @/ G* R4 o" X7 g
查询的时候就会拿着语句先去缓存中查询,如果能够命中就返回缓存的value,如果不命中就执行后面的阶段。
$ d7 Q( j! Z; v) t3 [* x3 t+ t3 s
7 i! c" Q7 T4 j' M
但是我还是不喜欢用缓存,因为缓存弊大于利。
3 e8 B2 A# X4 B# K! o5 x- g; u
. }' a2 I/ l; h: q8 b1 ]* y/ ]
哦?此话怎讲?
0 L% b' n2 |! k3 g$ T: G
缓存的失效很容易,只要对表有任何的更新,这个表的所有查询缓存就会全部被清空,就会出现缓存还没使用,就直接被清空了,或者积累了很多缓存准备用来着,但是一个更新打回原形。
8 Y" d* E5 O# n/ L
! j, Q8 P, y. j4 ]
这就导致查询的命中率低的可怕,只有那种只查询不更新的表适用缓存,但是这样的表往往很少存在,一般都是什么配置表之类的。
9 v: `. c$ Q3 [8 |% l& X0 n
6 t- `! {' x) c2 q
那我们查询的时候不想用缓存一般都是怎么操作的,或者是用缓存又怎么操作?
6 Y( V( {$ B3 v/ j8 y$ f. ^# f, j) t
可以显示调用,把query_cache_type设置成为DEMAND,这样SQL默认不适用缓存,想用缓存就用SQL_CACHE。
- F& X J$ L9 _& {' _. G% m, n9 J
0 C+ g) z9 `2 Q3 F; \$ w$ z
有个小技巧就是,我们之前开发的时候,都会去库里看看sql执行时间,但是可能是有缓存的,一般我们就在sql前面使用SQL_NO_CACHE就可以知道真正的查询时间了。
. s. F9 i+ `( C& t% Y% q
( Y4 Y3 k) p9 o( C
select SQL_NO_CACHE * from B
1 T* U$ t: b: _0 s. W8 l
缓存在MySQL8.0之后就取消了,所以大家现在应该不需要太关注这个问题,主要是我之前用的版本都不高,所以缓存一直有,在《高性能MySQL》书中也看到了一些关于缓存的介绍,就想起来给大家也提一下了。
/ d' m, J" @0 A' |/ H: f5 r
& \, w% d4 }; N7 Z
缓存查询完了应该做啥呢?
# a1 B+ G, K0 |9 G% ?/ q
在缓存没有命中的情况下,就开始执行语句了,你写的语句有没有语法错误,这是接下来MySQL比较关心的点。
9 b. W& l5 U5 I: s3 s" u/ `
+ f7 u5 Y3 m: h# F+ \% n2 ~
那他会怎么做呢?会先做词法分析,你的语句有这么多单词、空格,MySQL就需要识别每个字符串所代表的是什么,是关键字,还是表名,还是列名等等。
( m; L6 B! f6 E- F" \
1 f0 P$ O" t. ^5 e6 g4 C# g
然后就开始语法分析,根据词法分析的结果,语法分析会判断你sql的对错,错了会提醒你的,并且会提示你哪里错了。
* D4 z5 F: s" K) \/ m' y
2020-4-28 15:19 上传
下载附件
(28.19 KB)
6 `2 C- S7 ]" {+ R( g
分析没错之后就进入下一步,优化器。
9 E( Y+ ?2 _, n& R R+ Y
* T5 V7 R! ]! t* Z, Z
主要是优化什么呢?
. ]! h+ m7 F" K J
优化就比较简单了,因为我们建立表可能会建立很多索引,优化有一步就是要确认使用哪个索引,比如使用你的主键索引,联合索引还是什么索引更好。
+ z. ]4 G* x" o: B, D
) c7 C9 F( B2 z+ N8 I0 R
还有就是对执行顺序进行优化,条件那么多,先查哪个表,还是先关联,会出现很多方案,最后由优化器决定选用哪种方案。
" f, X/ b% O8 U+ E" ^; O8 T
% j" v, `( C* \* n: O
最后就是执行了,执行就交给执行器去做。
Q# \- ~6 n$ ]2 ?9 t" n( z- B9 R+ ?
0 ~& n: P1 Q4 h% X/ O6 x% p3 h
第一步可能就是权限的判断,其实这里我不确定的一个点就是,我接触的公司很多都是自研的线上查询系统,我们是不能用Navicat直连线上库,只能去网页操作,那表的权限是在MySQL层做的,还是系统做的,我猜应该是系统层做的,MySQL可能默认就全开放了,只是我们 不知道ip。
# X# d& U' H6 k' }+ m/ b- Z9 q g; c$ a
/ p/ [0 O: b8 U6 y: f R. i& v4 x
有知道的小伙伴也可以在公众号【三太子敖丙】去加我微信跟我说。
, q( J. `" z8 o; J
! F5 E! Z( }/ L! D% `" }
执行的时候,就一行一行的去判断是否满足条件,有索引的执行起来可能就好点,一行行的判断就像是接口都提前在引擎定义好了,所以他比较快。
0 c2 z% f$ R" Q! \/ O( P
% v& \" G2 o" S- L' Z, M( Y9 D9 M
数据库的慢日志有个rows_examined字段,扫描多少行可以看到,还有explain也可以看到执行计划,我们扫描了多少行。
/ u4 I9 g$ m6 l; r. g& i
+ L. j4 ~$ F* F: U' d! Z) s" W/ ^
可以小伙子,基础大致框架还是了解得很清楚的,我们下次深入了解下,索引和部分机制。
& T7 b" b/ x* x# x7 C1 p- Q
好的,我们下次见。
# U- m! `& @7 C7 {. J
# U( O3 P: m0 D' m1 s+ `
总结
6 V r+ W6 r/ w4 k6 [+ L3 ~
3 y( g W, \ n' k4 X! U
基本上我把MySQL的逻辑架构的东西都简单聊了一遍,当然你去自信了解的话,你会发现其实里面还有很多细节的,我只是说了一些常见的问题,这还是阿里丁奇学长的《MySQL实战》的思路。
. f" v6 T, _9 C+ b) u: c
: Z3 d, j- ^. \. Q
我自己在MySQL方面更多的可能就是理论知识了,还做不到深入了解的地步,大家如果有机会一定要深入的去学习一下。
' K6 F" w2 B: |1 K0 f
————————————————
, i% ~. g( ^; X% q( k' Y* s; [! S
版权声明:本文为CSDN博主「敖 丙」的原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接及本声明。
+ i! D) S/ f0 ~; y. C+ n& I
原文链接:https://blog.csdn.net/qq_35190492/article/details/104203466
" a8 L9 T! z; l6 r8 Z$ l' o* ^
: G5 s/ ^6 g# k+ p
& n5 J4 C4 N- ]% R3 z8 W$ L
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5