组合索引(concatenated index):由多个列构成的索引,如create index idx_emp on emp(col1, col2, col3, ……),则我们称idx_emp索引为组合索引。

在组合索引中有一个重要的概念:引导列(leading column),在上面的例子中,col1列为引导列。当我们进行查询时可以使用”where col1 = ? ”,也可以使用”where col1 = ? and col2 = ?”,这样的限制条件都会使用索引,但是”where col2 = ? ”查询就不会使用该索引。所以限制条件中包含先导列时,该限制条件才会使用该组合索引。

创建2张测试表:

mysql> desc test1;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | varchar(45) | YES | MUL | NULL | |
| dept | varchar(50) | YES | | NULL | |
| desc | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec) mysql> desc test2;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| email | varchar(50) | YES | | NULL | |
| address | varchar(50) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec) mysql>

通过存储过程模拟一些数据:

delimiter $$
create procedure mock_insert_test1()
BEGIN
DECLARE v int DEFAULT 1;
WHILE v < 800000
DO
INSERT into test1
VALUES(v,CONCAT('name',v),CONCAT('dept',v),NULL);
SET v = v + 1;
END WHILE;
end
$$
delimiter ;
delimiter $$
create procedure mock_insert_test2()
BEGIN
DECLARE v int DEFAULT 1;
WHILE v < 800000
DO
INSERT into test2
VALUES(v,CONCAT('email',v),CONCAT('addr',v));
SET v = v + 1;
END WHILE;
end
$$
delimiter ;

执行存储过程灌一些数据,

mysql> SELECT * from test1 limit 10;
+----+----------+-------+------+
| id | name | dept | desc |
+----+----------+-------+------+
| 1 | duan | yanfa | NULL |
| 2 | zhangsan | renli | NULL |
| 3 | lisi | renli | NULL |
| 1 | name1 | dept1 | NULL |
| 2 | name2 | dept2 | NULL |
| 3 | name3 | dept3 | NULL |
| 4 | name4 | dept4 | NULL |
| 5 | name5 | dept5 | NULL |
| 6 | name6 | dept6 | NULL |
| 7 | name7 | dept7 | NULL |
+----+----------+-------+------+
10 rows in set (0.00 sec) mysql>

引导列是id时,索引是这样的:inx_id_name:id,name

创建索引后,

结果:

引导列是name时,索引是这样的:

结果:

为什么要以name为引导列?因为ID是join列,并且ID列上面没过滤条件,如果以ID列作为引导列,由于没过滤条件那么CBO只能走 index full scan,或者index fast full scan,因为引导列没过滤条件,走不了index range scan,  最多走index skip scan,不过index skip scan代价过高,因为index skip scan要求 引导列选择性很低,但是ID这里选择性很高。

如果name列作为引导列,那么优化器就可以选择index range scan,这样相比index full scan, index fast full scan肯定要少扫描很多leaf block,逻辑读就会相对较少。

其实到这里,是否可以总结一下建立组合索引的原则总结:

  1. 引导列要选择过滤条件的列作为引导列,比如 where a.xxx='xxx' 或者 a.xxx> 或者 a.xxx<
  2. 引导列的选择性越高越好,因为选择性越高,扫描的leaf block就越少,效率就越高  (正确的顺序依赖于使用该索引的查询,并且同时需要考虑如何更好的满足排序和分组的需要。在一个多列B-Tree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列。所以,索引可以按照升序或者降序进行扫描,以满足精确符合列顺序的ORDER BY、GROUP BY和DISTINCT等子句的查询需求。对于如何选择索引顺序有一个经验法则:将选择性较高的列放到索引的最前列。)
  3. 尽量把join列放到组合索引最后面

  

mysql索引之七:组合索引中选择合适的索引列顺序的更多相关文章

  1. Oracle数据库中如何选择合适的索引类型 .

    索引就好象一本字典的目录.凭借字典的目录,我们可以非常迅速的找到我们所需要的条目.数据库也是如此.凭借Oracle数据库的索引,相关语句可以迅速的定位记录的位置,而不必去定位整个表. 虽然说,在表中是 ...

  2. MySQL如何选择合适的索引

    先来看一个栗子 EXPLAIN select * from employees where name > 'a'; 如果用name索引查找数据需要遍历name字段联合索引树,然后根据遍历出来的主 ...

  3. mysql—数据库优化——如何选择合适的索引

    索引的分类: 普通索引: 唯一索引: 主键索引:特殊的唯一索引,唯一且不能有null值: 全文索引:全文索引用来对表中的文本域(char, varchar, text)进行索引 全文索引针对myisa ...

  4. SQL Server性能优化(15)选择合适的索引

    一.关于聚集索引列的选择(参考) 1. 聚集索引所在的列,或者列的组合最好是唯一的. 当我们创建的聚集索引的值不唯一时,SQL Server则无法仅仅通过聚集索引列(也就是关键字)唯一确定一行.此时, ...

  5. MySQL innodb的组合索引各个列中的长度不能超过767,

    MySQL索引的索引长度问题   MySQL的每个单表中所创建的索引长度是有限制的,且对不同存储引擎下的表有不同的限制. 在MyISAM表中,创建组合索引时,创建的索引长度不能超过1000,注意这里索 ...

  6. 一文带您了解 Elasticsearch 中,如何进行索引管理(图文教程)

    欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/ ...

  7. SQL Server 索引维护(1)——系统常见的索引问题

    前言: 在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次D ...

  8. MySQL单列索引和组合索引的选择效率与explain分析

    一.先阐述下单列索引和组合索引的概念: 单列索引:即一个索引只包含单个列,一个表可以有多个单列索引,但这不是组合索引. 组合索引:即一个索包含多个列. 如果我们的查询where条件只有一个,我们完全可 ...

  9. mysql数据库优化之 如何选择合适的列建立索引

    1. 在where 从句,group by 从句,order by 从句,on 从句中出现的列: 2. 索引字段越小越好: 3. 离散度大的列放到联合索引的前面:比如: select * from p ...

随机推荐

  1. 【洛谷 P4051】 [JSOI2007]字符加密(后缀数组)

    题目链接 两眼题.. 第一眼裸SA 第二眼要复制一倍再跑SA. 一遍过.. #include <cstdio> #include <cstring> #include < ...

  2. 聂老师的考验(反向bfs)

    题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?id=1121 这个题看起来要多次使用bfs,其实只要换个思维就会发现这就是一个简单的bf ...

  3. [IOS]VMware上虚拟机MAC安装XCode

    1:VMware上虚拟机MAC安装前 VMware上安装Xcode之后 2:安装Xcode过程:把Xcode复制到虚拟机桌面上 3:复制完成之后,双击Xcode_6.4.dmg 文件 4:把Xcode ...

  4. Java 中的静态内部类

    静态内部类是 static 修饰的内部类,这种内部类的特点是: 1. 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 2. 如果外部类的静态成员与内部类的成 ...

  5. Optimizing subroutine calls based on architecture level of called subroutine

    A technique is provided for generating stubs. A processing circuit receives a call to a called funct ...

  6. Linux内核模块编程可以使用的内核组件

    2.2.2 在阅读<深入Linux内核架构与底层原理> 作者:刘京洋 韩方,发现一些错误,有些自己的理解,特以此记录 1.工作队列(workqueue) 队列是一种可以先进先出的数据结构, ...

  7. TCP之connect

    1. connect函数: #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, ...

  8. 【设计模式】迭代器模式(Iterator )

    摘要: 1.本文将详细介绍迭代器模式的原理和实际代码中特别是Android系统代码中的应用. 纲要: 1. 引入迭代器模式 2. 迭代器的概念及优缺点介绍 3. 迭代器在Android源码中的应用 1 ...

  9. selenium===splinter模块和selenium异曲同工

    学习文档: http://splinter.readthedocs.io/en/latest/ 安装以后用它来实现163邮箱的登陆操作:*和selenium一样,splinter同样需要对frame进 ...

  10. perl 函数参数传递与返回值(一)

    perl 函数参数传递与返回值(一) http://www.cnblogs.com/tobecrazy/archive/2013/06/11/3131887.html