您的位置:首页 > 其它

物理查询优化之索引

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

1. 如何利用索引

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

● 索隐裂座位条件出现在WHERE、H***ING、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/H***ING 的条件中出现 “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.多个索引对索引使用的影响
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: