物理查询优化之索引

索引是建立在表上的,本质上是通过索引直接定位表的物理元组,加速数据获取的方式,所以索引优化应该归属到物理查询优化阶段。

1. 如何利用索引

通常查询优化器所使用索引的原则如下:

 索隐裂座位条件出现在WHERE、HAVING、ON 子句中,这样有利于索引过滤元组;

  索引列是被链接的表对象的列且存在于连接条件中;

 还有一些情况可以使用索引,如排序操作、在索引列上球MIN、MAX等。

1.1 示例:

create table A(a1 int unique,a2 varchar(10),a3 int); (a1列上创建隐含索引)

  对表做查询,没有列对象作为过滤条件(如出现在WHERE子句中),只能顺序扫描

    mysql> explain extended select * from A;
  +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------+
  | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
  +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------+
  |  1 | SIMPLE      | A     | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | NULL  |
  +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------+

   type = ALL 表示 顺序扫描或范围扫描,不是用索引,顺序扫描,直接读取表上的数据(访问数据文件)。

对表做查询,有列对象列且索引列作为过滤条件,可作为索引扫描

    mysql> explain extended select * from A where a1 >2;
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | A     | range | a1            | a1   | 5       | NULL |    1 |   100.00 | Using index condition |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+

    t ype = range 表示基于索引做范围扫描。Using index condition 表示尝试通过索引来获取

对表做查询,索引列被运算符“-” 处理,查询优化器不能再执行前进行取反操作,不可利用索引,只能顺序扫描。

select A.* from A where -A.a1 = -2; (不能利用索引)

select A.* from A where  A.a1 =  2; (利用索引)

对表做查询,选择条件不包括索引列,只能顺序扫描

 select A.* from A where A.a3 = 2;

 索引列参与了运算,不能使用索引

 select A.*from A whereA.a1 + A.a3 = 2;

 select A.*from A whereA.a1= A.a3 + 2;

 select A.*from A whereA.a1< 1+2;(可以使用索引)

 查询时,索引列对象座位过滤条件时,操作符是 <> 时,不可做索引扫描,如果是 < 或者 > 时,可以使用索引

    mysql> explain extended select A.* from A where A.a1 <> 2;(不使用索引)
    +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | A     | ALL  | a1            | NULL | NULL    | NULL |    2 |   100.00 | Using where |
    +----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+

    mysql> explain extended select A.* from A where A.a1 > 2;(使用索引)
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | A     | range | a1            | a1   | 5       | NULL |    1 |   100.00 | Using index condition |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+

 查询时,索引列对象座位过滤条件时,操作符是 between - and 时,可以使用索引

    mysql> explain extended select A.* from A where A.a1 between 1 and 2;
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    | id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | A     | range | a1            | a1   | 5       | NULL |    2 |   100.00 | Using index condition |
    +----+-------------+-------+-------+---------------+------+---------+------+------+----------+-----------------------+


1.2 所以,对于索引列,索引可用的条件如下:

在WHERE, JOIN/ON/HAVING 的条件中出现 “key <op> 常量” 格式的条件子句(索引列不能参与带有变量表达式的运算)

操作符不能是<>操作符(不等于操作符在任何类型的列上都不能使用索引)

索引列的选择率越低,索引越有效,通常认为选择率小鱼0.1的索引扫描效果会好一些


2. 索引列的位置对使用索引的影响

2.1 对目标列、WHERE 等条件子句的影响

索引列出现在目标列通常不可以使用索引(但不是全部情况),索引列出现目标列对查询语句的优化没有好的影响PostgreSQL,如:

select A.1a from A;(PostgreSQL

注意:具体的数据库可能存在差别,在我的mysql环境是可以用到索引的:如下:

mysql> explain extended select A.a1 from A;
+----+-------------+-------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | A     | index | NULL          | a1   | 5       | NULL |    2 |   100.00 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+------+----------+-------------+

聚集函数MIN/MAX 用在索引列上,出现在目标列中,可以使用索引PostgreSQL。如:

select MAX(A.a1) from A;(PostgreSQL

注意:具体的数据库可能存在差别,在我的mysql环境没有用到索引:如下:

mysql> explain extended select Max(A.a1) from A;
+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                        |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+------------------------------+
()

索引出现在JOIN/ON 子句中,作为连接条件,不可使用索引。但是索引列出现限制条件满足“key<op>常量”格式可用到索引。

 create table B(b1 int unique,b2 varchar(10),b3 int);

mysql> explain extended select A.*,B.* from A join B on a1 = b1;
+----+-------------+-------+------+---------------+------+---------+-----------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref       | rows | filtered | Extra       |
+----+-------------+-------+------+---------------+------+---------+-----------+------+----------+-------------+
|  1 | SIMPLE      | B     | ALL  | b1            | NULL | NULL    | NULL      |    1 |   100.00 | Using where |
|  1 | SIMPLE      | A     | ref  | a1            | a1   | 5       | test.B.b1 |    1 |   100.00 | NULL        |
+----+-------------+-------+------+---------------+------+---------+-----------+------+----------+-------------+

执行计划表示 对B表进行了全表扫描,对A表连接时使用了索引。

mysql> explain extended select A.*,B.* from A join B on a1 = b1 and a1 = 1;
+----+-------------+-------+-------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | type  | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+-------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | A     | const | a1            | a1   | 5       | const |    1 |   100.00 | NULL  |
|  1 | SIMPLE      | B     | const | b1            | b1   | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+-------+---------------+------+---------+-------+------+----------+-------+
对A和B都使用而索引。

还有些关于order by,group by 的,发现数据库不同的话存在差异,就不写了,

当然上面的也可能存在差异,具体的话在用的时候看下执行计划就知道了。

3. 联合索引对索引使用的影响

create table E(e1 int,e2 varchar(10),e3 int,e4 int,primary key(e1,e3,e4));

使用联合索引的前缀部分索引键,可触发索引的使用;

使用部分索引键,但不是联合索引的前缀部分,不可出发索引的使用。

select * from E where e1 = 1;

select * from E where e1 = 1 and e3 =1 ;(select * from E where e1 = 1 or e3 =1 ;这种情况不会用到索引)

select * from E where e1 = 1 and e3 =1 and e4 = 1;

以上三个都是可以使用索引的:

mysql> explain extended select * from E where e1 = 1;
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | E     | ref  | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)


mysql> explain extended select * from E where e1 = 1 and e3 =1;
+----+-------------+-------+------+---------------+---------+---------+-------------+------+----------+-------+
| id | select_type | table | type | possible_keys | key     | key_len | ref         | rows | filtered | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------------+------+----------+-------+
|  1 | SIMPLE      | E     | ref  | PRIMARY       | PRIMARY | 8       | const,const |    1 |   100.00 | NULL  |
+----+-------------+-------+------+---------------+---------+---------+-------------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)


mysql> explain extended select * from E where e1 = 1 and e3 =1 and e4 = 1;
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                               |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Impossible WHERE noticed after reading const tables |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-----------------------------------------------------+

注意:这里第三个看上去没有使用到索引,那是因为 e1 = 1 and e3 =1这两个条件过滤后就没有数据了,后面的e4=1不用看也知道返回false了。


下面的这种是不会用到索引的:

mysql> explain extended select * from E where e3 = 1 and e4 = 1;
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | E     | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+----------+-------------+

另外这种情况:虽然使用到了索引,但是只是使用到了e1这一列上的索引,e4=1 这里没有用到索引。

mysql> explain extended select * from E where e1 = 1 and e4 = 1;
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | E     | ref  | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+----------+-------------+


4.多个索引对索引使用的影响




发布了52 篇原创文章 · 获赞 8 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/wufengui1315/article/details/46659097