You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -394,33 +400,33 @@ ALTER TABLE table_name ADD KEY(column_name(prefix_length));
394
400
395
401
#### 多列索引(复合索引、联合索引)
396
402
397
-
在多个列上建立独立的单列索引大部分情况下并不能提高 MySQL 的查询性能。对于下面的查询where条件,这两个单列索引都是不好的选择:
403
+
**在多个列上建立独立的单列索引大部分情况下并不能提高 MySQL 的查询性能**。对于下面的查询 where 条件,这两个单列索引都是不好的选择:
398
404
399
405
```mysql
400
406
select film_id, actor_id from table1 where actor_id=1or film_id=1;
401
407
```
402
408
403
-
MySQL 5.0 版本之前,MySQL会对这个查询使用全表扫描,除非改写成两个查询UNION的方式。
409
+
MySQL 5.0 版本之前,MySQL会对这个查询使用全表扫描,除非改写成两个查询 UNION 的方式。
404
410
405
411
MySQL 5.0 和后续版本引入了一种叫做“**索引合并**”的策略,查询能够同时使用这两个单列索引进行扫描,并将结果合并。这种算法有三个变种:OR 条件的联合(union),AND 条件的相交(intersection),组合前两种情况的联合及相交。索引合并策略有时候是一种优化的结果,但实际上更多时候说明了表上的索引建得很糟糕:
@@ -436,7 +442,7 @@ MySQL 5.0 和后续版本引入了一种叫做“**索引合并**”的策略,
436
442
437
443
MySQL 有两种方式可以生成有序的结果,通过排序操作或者按照索引顺序扫描,如果 explain 的 type 列的值为index,则说明 MySQL 使用了索引扫描来做排序(不要和 extra 列的 Using index 搞混了,那个是使用了覆盖索引查询)。扫描索引本身是很快的,因为只需要从一条索引记录移动到紧接着的下一条记录,但如果索引不能覆盖查询所需的全部列,那就不得不扫描一条索引记录就回表查询一次对应的整行,这基本上都是随机 IO,因此按索引顺序读取数据的速度通常要比顺序地全表扫描慢,尤其是在IO 密集型的工作负载时。
438
444
439
-
MySQL 可以使用同一个索引既满足排序,又用于查找行,因此,如果可能,设计索引时应该尽可能地同时满足这两种任务,这样是最好的。只有当索引的列顺序和 order by 子句的顺序完全一致,并且所有列的排序方向(倒序或升序,创建索引时可以指定ASC或DESC)都一样时,MySQL 才能使用索引来对结果做排序,如果查询需要关联多张表,则只有当 order by 子句引用的字段全部为第一个表时,才能使用索引做排序,order by 子句和查找型查询的限制是一样的,需要满足索引的最左前缀的要求,否则 MySQL 都需要执行排序操作,而无法使用索引排序。
445
+
**MySQL 可以使用同一个索引既满足排序,又用于查找行,因此,如果可能,设计索引时应该尽可能地同时满足这两种任务,这样是最好的**。只有当索引的列顺序和 order by 子句的顺序完全一致,并且所有列的排序方向(倒序或升序,创建索引时可以指定ASC或DESC)都一样时,MySQL 才能使用索引来对结果做排序,如果查询需要关联多张表,则只有当 order by 子句引用的字段全部为第一个表时,才能使用索引做排序,order by 子句和查找型查询的限制是一样的,需要满足索引的最左前缀的要求,否则 MySQL 都需要执行排序操作,而无法使用索引排序。
440
446
441
447
442
448
@@ -478,6 +484,75 @@ MySQL 允许在相同列上创建多个索引,无论是有意的还是无意
1. 最左前缀匹配原则,非常重要的原则,MySQL 会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d 的顺序可以任意调整。
502
+
503
+
2. =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,MySQL 的查询优化器会帮你优化成索引可以识别的形式。
13. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
540
+
14. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:`select id from t where num is null` 可以在 num上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:`select id from t where num=0`
541
+
15. 应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
542
+
16. 应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:`select id from t where num=10 or num=20` 可以这样查询:`select id from t where num=10 union all select id from t where num=20`
543
+
17. in 和 not in 也要慎用,否则会导致全表扫描,如:`select id from t where num in(1,2,3)` 对于连续的数值,能用 between 就不要用 in 了:`select id from t where num between 1 and 3`
544
+
18. 下面的查询也将导致全表扫描:`select id from t where name like '李%'` 若要提高效率,可以考虑全文检索。
545
+
19. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:`select id from t where num=@num` 可以改为强制查询使用索引:`select id from t with(index(索引名)) where num=@num`
546
+
20. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:`select id from t where num/2=100` 应改为: `select id from t where num=100*2`
547
+
21. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:`select id from t where substring(name,1,3)='abc' `,name 以 abc 开头的 id 应改为: `select id from t where name like 'abc%'`
548
+
22. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
24. 不要写一些没有意义的查询,如需要生成一个空表结构:`select col1,col2 into #t from t where 1=0` 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(...)
551
+
25. 很多时候用 exists 代替 in 是一个好的选择:`select num from a where num in(select num from b)` 用下面的语句替换:` select num from a where exists(select 1 from b where num=a.num)`
0 commit comments