数学建模社区-数学中国
标题: mysql索引和explain的详解 [打印本页]
作者: 杨利霞 时间: 2020-5-3 15:46
标题: mysql索引和explain的详解
2 K3 z% n4 h, ], r0 \mysql索引和explain的详解索引原理分析
" }; }" u6 X- ?
& d3 k3 J+ }7 |3 v3 V" |6 W; |索引存储结构. }" D( P! A- X
索引是在存储引擎中实现的,也就是说不同的存储引擎,会使使用不同的索引" |* i% _* c5 |1 i; @
MyISAM和InnoDB存储引擎:只支持B+ TREE索引, 也不能够更换9 b9 y6 @& b2 v( H
MEMORY/HEAP存储引擎:支持HASH和BTREE索引
$ d B% q, u" e {! Y6 X$ c* m' o3 W6 a! d, y7 `# ]
B树图示
- f, y' [* `( }: Q1 q; W: E r; e+ Y( n0 G
B树是为了磁盘或其它存储设备设计的一种多叉(下面你会看到,相对于二叉,B树每个内结点有多个分支,即多叉)平衡查找树。 多叉平衡。
; r7 A5 {: _2 P" [& \5 v6 Q: _2 Y6 _& e }2 a) {. R+ ?
* i! Q7 B1 M1 ~& S( E4 G Y% g* B% q( `( o3 ~
0 ^" |2 R' ~! U. M4 @B树和B+树的区别:; m: ?- Z1 ~4 x1 v! W
B树和B+树的最大区别在于非叶子节点是否存储数据的问题
, w, m, R( R+ |% v' O0 u- [# l- h7 G1 y
# l6 [2 b* @5 n3 k$ e# [ \4 f在结构上:; G2 ]8 ` L9 f' C, o" _0 ^
(1) B树是非也只节点和叶子节点都会存储数据。0 E _6 f ^0 S# s+ Z/ \4 N: Y9 c3 W
(2) B+树只有叶子节点才会存储数据,而且数据都是在一行上,而且这些数据都是指针指向的,也是有顺序的。
3 S+ }! p: g1 m! [* G) g7 V, n. h5 I+ O" n, {7 o" V4 \
在性能上:) m1 ^$ L; s/ g% ~* v% s" ]
(1)对于B-树相对于B+数据,B-Tree因为非叶子结点也保存具体数据,所以在查找某个关键字的时候找到即可返回。而B+Tree所有的数据都在叶子结点,每次查找都得到叶子结点。所以在同样高度的B-Tree和B+Tree中,B-Tree查找某个关键字的效率更高。B-Tree在单条数据读写有着更强的性能。
( R' ^! v0 B' G- i6 W5 ~" l(2)但由于B+Tree所有的数据都在叶子结点,并且结点之间有指针连接,在找大于某个关键字或者小于某个关键字的数据的时候,B+Tree只需要找到该关键字然后沿着链表遍历就可以了,而B-Tree还需要遍历该关键字结点的根结点去搜索。这个也决定当连表查询的时候mysql比起mongo有显著的优势。更重要的是由于B-Tree的每个结点(这里的结点可以理解为一个数据页)都存储主键+实际数据,而B+Tree非叶子结点只存储关键字信息,而每个页的大小有限是有限的,所以同一页能存储的B-Tree的数据会比B+Tree存储的更少。这样同样总量的数据,B-Tree的深度会更大,增大查询时的磁盘I/O次数,进而影响查询效率。! d' E- C# _+ Q
7 f4 b" S$ O) h
聚集索引(MyISAM). F7 |% \5 u/ h$ ?5 F5 b
B+树叶节点只会存储数据行(数据文件)的指针,简单来说数据和索引不在一起,就是聚集' d+ h. \$ M/ {6 @, e! [% `
索引。
/ H7 N- ], ^" L2 K" p聚集索引包含主键索引和辅助索引都会存储数据指针的值。
) F" m. k$ _' t* m, T$ f6 Z
+ s( \* `0 X3 z# W
5 y4 g# F1 ~* c+ k7 h
& m0 U J( d) h
辅助索引(次要索引)) X, r2 Q/ c2 W# }- V5 a$ M( Q
在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求 key 是唯一的,
7 j! H' {+ B8 d# w9 ~% T而辅助索引的 key 可以重复。如果我们在 Col2 上建立一个辅助索引,则此索引的结构如下图所示
. M+ j& ~- P& E: K+ r
( D5 J) B* A9 R! M' x( T9 Y0 I' C同样也是一颗 B+Tree,叶子节点中保存数据记录的地址。因此,MyISAM 中索引检索的算法为首先按照B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其data 域的值,然后以 data 域的值为地址,读取相应数据记录。# x3 S7 P' f* @
( z' j F U. u% \9 @2 W
聚集索引(InnoDB)
3 O' [' v" o! O9 }2 [/ a5 T O. H% b9 `7 ~6 P4 M5 p. b% {7 D
主键索引(聚集索引)的叶子节点会存储数据行,也就是说数据和索引是在一起,这就是聚集索引。
; C2 e! U' e+ K. z( ^" F, b辅助索引只会存储主键值
) h/ a; }1 z1 r! T6 f8 i" A如果没有没有主键,则使用唯一索引建立聚集索引;如果没有唯一索引,MySQL会按照一定规则创建聚集索引。9 A$ d3 \' r7 o6 x1 R: n0 n1 I
$ n: G6 m; @0 Q; w x0 S
主键索引7 c5 E5 |0 ?: f/ ?; E. @4 E
1.InnoDB 要求表必须有主键(MyISAM 可以没有),如果没有显式指定,则 MySQL系统会自动选择一个可以
0 J4 ] A1 ~9 U: s5 |- N唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,类型为长整形。' ]/ \* y% H: I( {# ]1 v1 X2 I, q
' |* T. p; z9 l! z
. F5 _; d" J1 v3 d( ~/ I0 [
; v4 |3 y* w: I* Q
% x, ~8 m: M0 d# B9 x
上图是 InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为 InnoDB 的数据文件本身要按主键聚集。
/ ?: [( I! P# K; s/ [1 [
0 i* \; H' y& k/ M: C
# { o# e; X! G, u6 x! i, f* f+ V/ g
1 k8 |% h1 q( N* R8 {( K. C9 O
6 K7 I `; k" s1 {- t5 i# b. P+ c* \
! ]9 q7 d) G( z, t( O) Pmysql创建索引的时候和用法与索引息息相关,要建立合适的索引和理解一些索引的执行计划,就需要认识索引的结构。
$ _$ Y3 T. E' \+ K7 l$ B1 c2 h
1 }3 I1 x+ [; dexplain的详解
( b& j# a' o( i) E1 g# S$ P6 T4 ?9 i X% Z' K$ \, W
参数说明:$ K- }7 N& T' E2 U" L
explain后会出现十列数据,下面将介绍这下面的十列数据。
' o" s2 Y. ~6 c/ [+ \
1 ^, m _' k$ }# S) Q) Tid、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra
! e& {3 q7 g7 y0 c9 Z" g) n6 O) [. b5 h; T% V# P7 T; \9 ^& ~+ v
先附上案例表:& T, }* H. z1 P2 F: o
) y8 u- h. G( L: [* ~CREATE TABLE `taddr` (
0 X3 Y6 Z- ?# S" D `id` int(11) NOT NULL AUTO_INCREMENT,
. T+ q% T" R; @* s, Y `country` varchar(100) DEFAULT '',! Z# |8 D3 W- L! h' N! Z+ O
`province` varchar(100) DEFAULT '',
- Z2 H/ [: F. {/ K* i1 _$ l7 a PRIMARY KEY (`id`)0 P6 D9 G0 s5 U- o! P) e1 N9 _6 z
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8% F: v9 N; H6 O* A4 z3 n
- L T6 H: e, o7 e7 R% w: DCREATE TABLE `user` (
& c- E! W! e r7 r& k5 L5 } `id` int(11) NOT NULL AUTO_INCREMENT,
! J1 L: C9 T/ O- B6 }# q `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
8 d& z2 Z& m: J0 h4 y `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,7 A3 U n! \8 Y3 j$ _
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,' S1 {9 u) J, X3 q9 l$ f0 M v
`addr_id` int(11) NULL DEFAULT NULL,- U. r5 x }# R" C5 P
PRIMARY KEY (`id`) USING BTREE,7 u$ w9 f+ {+ K
INDEX `addr_id`(`addr_id`) USING BTREE! O+ L0 C4 B7 z7 k# v2 d+ k/ f, C
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;( O: o4 N$ r7 ?; c* e
5 T) t( T( a, m( O* t& z6 Q
8 l- f5 ~1 C6 N1 v# Z6 D5 |CREATE TABLE `type_time` (
! G2 q4 v5 d2 `; D- f `id` int(11) NOT NULL AUTO_INCREMENT,9 F# G+ [# u# E. q1 |
`time` varchar(255) DEFAULT '[]',. c! k4 H/ g. ^- d( u0 G3 U
`name` varchar(100) DEFAULT '',
, Y: S8 ^$ ]8 i$ a- Q8 [( ? PRIMARY KEY (`id`),
4 i% m5 [& ^( j5 V INDEX `name_time_index`(`name`,`time`) USING BTREE
- e& p0 q, l4 u f% O- H, F- b) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf81 l) u7 `* U# j1 w
7 z9 R8 a5 i3 ?& a; G一、id
# Q4 E. w. ~% J3 T9 e0 o; S. Q每个 SELECT语句都会自动分配的一个唯一标识符.
% [% `0 c# w% ] |- L* T表示查询中操作表的顺序,有三种情况:
- O# L. W% D+ R% u+ t& \1 Jid相同:执行顺序由上到下
; P# M* I. p2 j5 uid不同:如果是子查询,id号会自增,id越大,优先级越高。7 i G6 `, e; j1 V7 H) M( T; u
id相同的不同的同时存在- `# f' s, R' @1 i
id列为null的就表示这是一个结果集,不需要使用它来进行查询。
: @0 u* T" o: y) D' F' y2 L& L* Q6 z+ z1 N6 j
二、select_type* p) `; F$ F5 G C0 P) G' M0 ?
) _/ |2 r! Q+ A; _4 S2 U8 l
查询类型,主要用于区别普通查询、联合查询(union、union all)、子查询等复杂查询
1 |( I$ T# f* K! K; ~6 N; k2 F; s* x3 q- l
2.1、simple
2 H" H# F9 L4 N* Z. l- I( e% T& K表示不需要union操作或者不包含子查询的简单select查询。有连接查询时,外层的查询为simple
1 u; S4 L y' B
8 n- Y7 ]: ]: i/ A( x6 }! E, hEXPLAIN select * from user/ o/ Z6 s% a6 ~# ~- H4 y
, b- C9 H% U/ M. g. _7 ~
* B2 f" c, t& H4 @
+ v2 h& c' [$ ~& oEXPLAIN select u.id,u.addr_id,a.* from user u inner join taddr a on u.addr_id=a.id
Q$ U2 i8 i; s2 |2 `* J
, r S7 M: y. V$ K8 i: {/ T
9 B9 A5 m, b& ]3 I9 j5 w" J2.2 primary$ Y. J1 A5 i, m: m0 E& ^; B* o
一个需要union操作或者含有子查询的select,位于最外层的单位查询的select_type为primary。. o" n% `5 l [
6 A% H% d+ h+ z' j/ J% w hexplain select * from taddr t inner join (% J: K6 ^. z; b( z* v8 m" c" T' k
select addr_id from user ) u on t.id=u.addr_id7 X- l9 d# z r- ?% z' i" f+ B5 k
4 l. N2 E* l$ c- w
explain select * from user u where u.addr_id =1q o" [$ H5 ]; E2 s
union all
9 T* p/ b0 X+ c1 i; Qselect * from user u where u.addr_id =2# q M4 O9 N* o+ B7 F
$ R- s5 m( d; J: |$ X& X& g
) v6 C& _, Q& r( L2.3 subquery/ U" W5 i( f Y' g2 P( V
除了from字句中包含的一查询外,其他地方出现的子查询都可能是subquery( o8 d+ ^! f! E7 D' \" m- `. h; V: u
: r' t, @3 d8 _. M1 d: Y2.4 dependent subquery; l4 b' j1 C9 X8 j
3 b$ v( g. D( `% k. u/ ]
与dependent union类似,表示这个subquery的查询要受到外部表查询的影响2 Y" n, `3 {9 M9 Q& ~( ^
& ^# ~& S3 o7 u8 g/ m% [% [6 U% \2 iexplain select u.name,(select t.province from taddr t where u.addr_id=t.id) from user u& X) G9 S v( j( Q
% q! q% n: u& V% k! j
2.5 union' }- J7 D( {4 o/ K) G& M0 n
union连接的两个select查询,第⼀个查询是PRIMARY,除了第一个表外,第二个以后的表select_type都是union
" p7 Y' J. |& H
- f5 U* G$ j% @1 b; j( O h" {1 S三、table# \8 d6 c0 o# h. W, H
显示的查询表名,如果查询使用了别名,那么这里显示的是别名7 o9 `' Z( B# }7 `8 O
如果不涉及对数据表的操作,那么这显示为null L: H* }1 p: ]8 G$ y
如果显示为尖括号括起来的就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生。1 b6 L7 \ `9 [" z* q
如果是尖括号括起来的<union M,N>,与类似,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集。% z5 U, N- i" Q; Q/ X4 d" e
3 S& c) M2 s- r9 U6 i0 B
四、type
$ h a! y8 c2 g. q( }
! j- T- _/ e1 M2 X' V0 h& p依次从好到差:
2 \& {6 S7 N- Osystem,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,& i, a1 F+ ?$ o! E( I% l
index_subquery,range,index_merge,index,ALL
! [1 J( s' P# O, V% ]+ u# S
/ s. S A# \+ T B& @: V3 H除了all之外,其他的type都可以使⽤到索引,除了index_merge之外,其他的type只可以用到一个索引
4 f7 B2 C, m1 q& i6 l& V0 D3 Q/ d+ r1 E( N: p- u" k! k. l, }# |1 H( W/ N
4、1 system$ Y: e# R P' c, [5 D. l
表中只有一行数据或者是空表。5 T, M6 Z% k* d: \: M) `
8 L m" f' x1 n
4、2const
/ G( \1 }/ ` }) B使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描。 {) d; C3 R" n M
& [' f4 m7 {# Q0 c4、3 eq_ref
! v' ^8 A* Q2 d$ Z1 Y关键字:连接字段主键或者唯一性索引。" m2 z5 s; v) O3 K. Z! W
此类型通常出现在多表的 join 查询, 表示对于前表的每一个结果, 都只能匹配到后表的一行结果. 并且查询的比较较操作通常是 ‘=’, 查询效率较高. S" m, v8 i- P4 @ z+ V
2 S" ~4 m: Z0 h& K5 x" m( w+ XEXPLAIN select u.id,u.addr_id,a.* from user u inner join taddr a on u.addr_id=a.id
% ~" }( s$ G" J6 a+ j6 y
1 Y" @' P h6 Z) V* e9 m9 N) R9 h9 Q% ^' G2 ~2 c h+ d3 t$ z. U
/ k' Z5 S9 S3 x/ W+ X; e; ^
; |/ N( E% ]6 g n
6 ^% {# n3 z5 F9 z) [4、4 ref
) L8 w" d* L) o& z( r: w5 }0 G针对非唯一性索引,使用等值(=)查询非主键。或者是使用了最左前缀规则索引的查询。
EXPLAIN select u.id,u.addr_id,a.* from taddr a left join user u on u.addr_id=a.id
- [8 F5 G1 z" I; ]! D" r( i8 f9 T* C
4 X& Z5 x; g4 G! `, i# w
4.5 fulltext% U* u) Z/ f6 B8 a+ O$ s
全文索引检索,要注意,全文索引的优先级很高,若全高索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引0 B( q' {- A l3 t' @; `8 A1 s
8 `/ O' j% I9 V* I: q. j
4、6 unique_subquery
" |* U2 H! A; J# ]6 D- H; G# f D8 f+ L用于where中的in形式子查询,子查询返回不重复值唯一值
, l& e: x# ~; c+ b6 h$ e( |9 }" c3 G) p( P
4、7 index_subquery
- y- z, D% y; H用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。6 D, G: p. c2 Z- X
6 T) i5 r0 {" U$ M7 P4 H. @6 j2 |: r
4、8 range! ]+ }; W+ T" L3 B/ G
索引范围扫描,常用于使用>,<,is null,between ,in ,like等运算符的查询中。
L( {- z" X& X6 _0 z& x5 z$ n5 e, E% b' L- m# s0 `; }
explain select * from type_time a inner join (8 S. c6 T) ]! R1 Z' F
select id from type_time where name =‘2’ and time in (‘2’,‘3’,‘4’) ) b on a.id=b.id& l- C) K/ ?0 K4 U7 V
' a. I5 b# w: j' l$ K% L
' {* V8 b' P% u% l% C+ b# t' t
' g- \' F. Q; V2 z' w9 o; D" I/ Z2 p3 i
4、9 index: \: T& h _/ q7 n* d: }
键字:条件是出现在索引树中的节点的。可能没有完全匹配索引。
9 i& s, O2 R9 C+ m7 U X索引全表扫描,把索引从头到尾扫一遍,常用于使用索引列就可以处理不需要读取数据文件的查询、可以使使用索引排序或者分组的查询。; Q: H# M6 k# @3 n* V
) w b! q% K" H0 G4 kexplain select * from user group by addr_id" f5 V1 v( x! _( r! d; \- B- L
. X! D( q( @3 U0 e. o! _
2 J2 e" U( X. p
2 a7 B. ?2 X. ?+ ]
! L! n4 j f; F9 y9 l+ ?& K3 y
/ m$ [* U9 b5 X
explain select addr_id from user
: y# H3 Z1 j! O$ ^
i- P/ M+ Y0 o9 G$ V0 \
; I4 o5 l# R- } a/ H7 H% v* H$ W2 i: I; _) W, b5 L1 f0 T
1 f: q$ c+ q% w" p4 c0 e3 a9 Y4、10 all
B4 z+ m( }7 x) [: b$ a3 L$ k+ D, Y1 c这个就是全表扫描数据文件,然后再在server层进行过滤返回符合要求的记录。( q$ N, K" k4 a, J8 K$ A
9 [8 R% {9 r* Y6 o& M5 O; j五、possible_keys
4 I: l- J3 g0 S4 t r q* z2 Q' V C9 F# r/ M% |* _/ w3 b
此次查询中可能选用的索引,一个或多个
3 i# ? k8 N- Z3 l$ x' O' O1 r. j$ w: M& G- W9 E
六、key
6 ?1 Q3 a) H# x查询真正使使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。
' A( k4 C8 E6 D* n. q, F2 [' @; B+ T+ \
七、key_len
$ ~* q. M+ h, ~% F1 m x
; X6 G% x5 f0 q" x0 ?% y用于处理查询的索引长度度,如果是单列索引,那就整个索引长度算进去,如果是多列索引,那么查+ s7 F1 [ d: Q6 ^0 Z/ m
询不一定都能使用到所有的列,具体使用到了多少个列的索引,这里就会计算进去,没有使用到的,这里不会计算进去。留意下这个列的值,算下你的多列索引总长度就知道有没有使用到所有的列了。4 |5 l I9 ~1 P6 P6 ~& L
另外,key_len只计算where条件用到的索引长度,而排序和分组就算使用到了索引,也不会计算到key_len中。4 t. ~) `6 O/ \( r* ^% k! z i
explain select id from type_time where name =‘2’ 用到长度303
: q3 [$ R# |0 ]9 z; Z" T3 ^% @7 c# h! [) u9 l! J
6 t4 w4 ^; k1 o% d1 x7 j/ F
explain select id from type_time where name =‘2’ and time in (‘2’,‘3’,‘4’) 用到长度 1071) C Q8 w( ^6 b( `) U3 J" j( e7 L
( m4 [( f; q: h7 E
$ r) |( }7 @/ Z' S/ {
1 G) I( ^" A. J
八、ref' p$ r+ a1 E7 c; T9 f6 w
如果是使用的常数等值查询,这里会显示const( Q. g$ F! d9 E# s( O4 Z7 g3 c
如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段
" H' Y2 j" y. M2 A. Z% Y" s0 L/ q6 a如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func
2 s4 }4 m% _' J- E" ~% O$ ?; b8 V# f5 H' {' v
九、rows
* o$ `& N& a5 S这里是执行计划中估算的扫描行数,不是精确值(InnoDB不是精确的值,MyISAM是精确的值,主要原因是InnoDB使用了MVCC并发机制)
. c# z( v( |9 M8 f8 N
( X# W) b3 K/ l0 G# u十、extra
7 m8 d, P) G2 t这个列包含不适合在其他列中显示但十分重要的额外的信息,其中比较常见有一些:4 ~& ?8 O; K( Q
% h: P2 a( l/ f# q10、1 using temporary/ i; W9 Z* t! `" G' [
表示使用了临时表存储中间结果。
% E' |% }% |' y. H/ N" a% C: MMySQL在对查询结果order by和group by时使用临时表
2 ?1 ~) }! R1 V* N% ^4 u临时表可以是内存临时表和磁盘临时表,执行计划中看不出来,需要查看status变量,0 V! X; D+ e, X) P
used_tmp_table,used_tmp_disk_table才能看出来。
! e9 S- `( |6 u: _* g; X$ s- s. Q* W7 Q/ o/ Y; j6 t# D% }
explain select * from user u inner join taddr t on u.addr_id=t.id GROUP BY t.id* I8 r; B' ]& d9 K- `+ U: Y
0 c. D; M" _7 e1 s9 b/ g2 w
8 b- t7 c7 e) J
* M5 q F5 I& N7 U2 F' A10、2 using filesort+ ]4 b, N5 P# a! X
排序时无法使用到索引时,就会出现这个。常用于order by和group by语句中
" Z2 c0 s. C' ~6 l" ^* j6 l2 a% \
4 A3 e+ u) M ^& N+ e3 X6 N+ A说明MySQL会使用个外部的索引排序,而不是按照索引顺序进行读取。+ s1 _' @2 a9 g
MySQL中无法利索引索引完成的排序操作称为“文件排序“8 i: t$ o4 o- r3 ^! L0 ?+ N( Z
* _ o6 z" n+ S }+ m% g
10、3 using index
6 |! Q) p3 D3 q+ E查询时不需要回表查询,直接通过索引就可以获取查询的数据。4 G+ F$ y0 ^3 H* V
表示相应的SELECT查询中使用到了覆盖索引(Covering Index),避免回表访问数据行,效率不& n9 H# R, p8 W& R
错。$ ?1 |0 V* E# C) h/ Y
如果同时出现Using Where ,说明索引被用来执行查找索引键值
3 r# ?' \4 \# t. q- O9 h( T如果没有同时出现Using Where ,表明索引用来读取数据来执行查找动作。* V( F- n7 N. \8 w, b
( @; H) ? Q$ I, S) r
这里对索引的原理和explain做了一些介绍,需要索引需要建立之后对其改变查询方式可能会更能深刻理解 InnoDB 使用覆盖索引和非覆盖索引造成区别。这也是建立索引和使用sql需要特别考虑的问题。
0 X, ^6 N, X: R( U* j9 G8 i————————————————2 H, h' a9 ]8 O9 F
版权声明:本文为CSDN博主「筏镜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 M' u5 G# m: }- o9 ]$ }: H& E
原文链接:https://blog.csdn.net/fajing_feiyue/article/details/105616629: B( x( ?/ g+ Q& U: e `
/ j4 e5 `6 R# d0 h' W% n" u% ^ v u% l) G ~3 c9 X" }! J
-
20.png
(13.61 KB, 下载次数: 425)
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) |
Powered by Discuz! X2.5 |