mysql中index与Multiple-Column Indexes区别与联系

索引对提高SELECT/UPDATE语句查询速度有着立竿见影的效果,有索引和无索引,查询速度每每差几个数量级。html

本次讨论一下index(每列做为一个索引,单列索引)和Multiple-Column Indexes(多列做为一个索引,最多16列,复合索引)使用场景。mysql

常见新建或添加索引的方式:

方式一,建表时新建sql

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
--  单列索引
    INDEX name (last_name)
-- 复合索引
-- INDEX name (last_name,first_name)
);

方式二,给即存表添加索引:ide

/*单列索引*/
ALTER TABLE test ADD INDEX name (last_name);
/*复合索引*/
ALTER TABLE test ADD INDEX name (last_name,first_name);

这里要注意索引的顺序很重要,关系到可否命中索引,后面详细讨论。工具

mysql官方文档是这么描述复合索引的:mysql能使用复合索引来查询索引中的全部列,或者查询复合索引中的第一列、前两列、前三列等等。优化

 若是指定列顺序正确相对于索引中的定义顺序,那么一个简单的复合做引能够加快一个表中几种类型的查询。官网地址spa

以上这段话包可解读以下:code

  • 复合索引的优势:一个复合索引解决多种查询的效率问题
  • 复合索引的命中规则:前半句话描述的是命中复合索引的最左前缀(leftmost prefix)规则,也就是上面提到的索引顺序问题。这个规则是对于WHERE语句中的索引列的顺的。

简单的说加入复合索引的顺序是(col1, col2, col3)那么WHERE语句中的(col1)、(ol1, col2)、(col1, col2, col3)都能命中索引,可是(col2)、(col3)、(ol2, col3)是不能命中索引规则的,由于不知足最左前缀规则。htm

举个栗子,假设新建复合索引以下:blog

CREATE TABLE test (
    id         INT NOT NULL,
    last_name  CHAR(30) NOT NULL,
    first_name CHAR(30) NOT NULL,
    PRIMARY KEY (id),
    INDEX name (last_name,first_name)
);

根据最左前缀原则,如下查询语句能命中索引:

SELECT * FROM test WHERE last_name='Widenius';
 
SELECT * FROM test
  WHERE last_name='Widenius' AND first_name='Michael';
 
SELECT * FROM test
  WHERE last_name='Widenius'
  AND (first_name='Michael' OR first_name='Monty');
 
SELECT * FROM test
  WHERE last_name='Widenius'
  AND first_name >='M' AND first_name < 'N';

如下查询语句不能命中复合索引:

SELECT * FROM test WHERE first_name='Michael';
 
SELECT * FROM test
  WHERE last_name='Widenius' OR first_name='Michael';

若是不清楚是否命中索引,EXPLAIN是个好工具,要充分利用起来。好比下语句,查看结果中的key就能知道是否命中,为空就是木有命中:

EXPLAIN SELECT * FROM test WHERE first_name='Michael';

使用场景:

在作报表集计通常会使用ETL工具抽取业务数据插入到事实表中,就好比使用kettle update/insert,其内部原理都是先查询不存在就如插入数据,存在数据就更新。

所以若是数据不少的话就会有不少的查询动做,而且是多条件查询。这种状况复合索引效率是最高的,可是每每实际的业务中还会以单列做为查询的场合这是就须要普通索引来知足这个需求。

这种场合就会出现同一列同时出如今了复合索引和单列索引中,这也是很正常的。给一个实际的例子以下:

CREATE TABLE `st_stock` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `id_company` int(11) NOT NULL COMMENT '组织维度',
  `id_date` int(11) NOT NULL COMMENT '日期维度',
  `id_part` int(11) NOT NULL COMMENT '材料维度',
  `number` decimal(18,2) DEFAULT NULL COMMENT '出库数量',
  `subtotal` decimal(21,6) DEFAULT NULL COMMENT '出库金额',
  PRIMARY KEY (`id`),
  KEY `IDX_ORG` (`id_company`),
  KEY `IDX_PART` (`id_part`),
  KEY `IDX_DATE_ORG_PART` (`id_date`,`id_company`,`id_part`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='xxxxxx';

实际疗效:

 

#2498和#2499数据量大于等于#249六、#2497,但集计时间将近缩短了一半,效果仍是很明显。

优化效果没有达到一个数量或更高级是由于优化的只是JOB中一个转换,只是优化的众多因素之一。

即使如此也达到了预期的效果。

 

最后还要注意一点,索引的维护是有代价的,并非越多越好。其余参考资料以下:

https://www.percona.com/blog/2009/09/19/multi-column-indexes-vs-index-merge/

https://www.percona.com/blog/2014/01/03/multiple-column-index-vs-multiple-indexes-with-mysql-56/

https://dev.mysql.com/doc/refman/5.7/en/drop-index.html

https://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html

https://dev.mysql.com/doc/refman/5.7/en/create-index.html

相关文章
相关标签/搜索