@@ -177,6 +177,30 @@ MySQL的优化主要分为结构优化(Scheme optimization)和查询优化
177
177
显然这个查询等价于查询emp_no为10001的函数,但是由于查询条件是一个表达式,MySQL无法为其使用索引。看来MySQL还没有智能到自动优化常量表达式的程度,因此在写查询语句时尽量避免表达式出现在查询中,而是先手工私下代数运算,转换为无表达式的查询语句。
178
178
179
179
### 索引选择性与前缀索引
180
+ 既然索引可以加快查询速度,那么是不是只要是查询语句需要,就建上索引?答案是否定的。因为索引虽然加快了查询速度,但索引也是有代价的:索引文件本身要消耗存储空间,同时索引会加重插入、删除和修改记录时的负担,另外,MySQL在运行时也要消耗资源维护索引,因此索引并不是越多越好。一般两种情况下不建议建索引。
181
+ * 第一种情况是表记录比较少,例如一两千条甚至只有几百条记录的表,没必要建索引,让查询做全表扫描就好了。至于多少条记录才算多,这个个人有个人的看法,我个人的经验是以2000作为分界线,记录数不超过 2000可以考虑不建索引,超过2000条可以酌情考虑索引。
182
+ * 另一种不建议建索引的情况是索引的选择性较低。
183
+ > 所谓索引的选择性(Selectivity),是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:
184
+ Index Selectivity = Cardinality / #T
185
+
186
+ 显然选择性的取值范围为(0, 1] ,选择性越高的索引价值越大,这是由B+Tree的性质决定的。例如,上文用到的employees.titles表,如果title字段经常被单独查询,是否需要建索引,我们看一下它的选择性:
187
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-22.png )
188
+ title的选择性不足0.0001(精确值为0.00001579),所以实在没有什么必要为其单独建索引。
189
+ 有一种与索引选择性有关的索引优化策略叫做前缀索引,就是用列的前缀代替整个列作为索引key,当前缀长度合适时,可以做到既使得前缀索引的选择性接近全列索引,同时因为索引key变短而减少了索引文件的大小和维护开销。下面以employees.employees表为例介绍前缀索引的选择和使用。
190
+ 可以看到employees表只有一个索引<emp_no>,那么如果我们想按名字搜索一个人,就只能全表扫描了:
191
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-23.png )
192
+ 如果频繁按名字搜索员工,这样显然效率很低,因此我们可以考虑建索引。有两种选择,建<first_name>或<first_name, last_name>,看下两个索引的选择性:
193
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-24.png )
194
+ <first_name>显然选择性太低,<first_name, last_name>选择性很好,但是first_name和last_name加起来长度为30,有没有兼顾长度和选择性的办法?可以考虑用first_name和last_name的前几个字符建立索引,例如<first_name, left(last_name, 3)>,看看其选择性:
195
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-25.png )
196
+ 选择性还不错,但离0.9313还是有点距离,那么把last_name前缀加到4:
197
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-26.png )
198
+ 这时选择性已经很理想了,而这个索引的长度只有18,比<first_name, last_name>短了接近一半,我们把这个前缀索引建上:
199
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-27.png )
200
+ 此时再执行一遍按名字查询,比较分析一下与建索引前的结果:
201
+ ![ 索引选择性与前缀索引] ( /img/database-index/database-index-28.png )
202
+ 性能的提升是显著的,查询速度提高了120多倍。
203
+ > 前缀索引兼顾索引大小和查询速度,但是其缺点是不能用于ORDER BY和GROUP BY操作,也不能用于Covering index(即当索引本身包含查询所需全部数据时,不再访问数据文件本身)。
180
204
181
205
接下来我们从结构优化和查询优化两方面来了解一些具体的优化手段:
182
206
### 结构优化
0 commit comments