物理查询优化之索引

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

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.多个索引对索引使用的影响

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-01 00:57:50

物理查询优化之索引的相关文章

MySQL物理查询优化技术---index dive辨析

一 引子 在MySQL的官方手册上有这么一句话: the optimizer can estimate the row count for each range using dives into the index or index statistics. 这是在说: 优化器为每一个范围段(如"a IN (10, 20, 30)"是等值比较, 括3个范围段实则简化为3个单值,分别是10,20,30)估计每个范围段(用范围段来表示是因为MySQL的"range"扫描方

数据库查询优化——Mysql索引

工作一年了,也是第一次使用Mysql的索引.添加了索引之后的速度的提升,让我惊叹不已.隔壁的老员工看到我的大惊小怪,平淡地回了一句"那肯定啊". 对于任何DBMS,索引都是进行优化的最主要的因素.对于少量的数据,没有合适的索引影响不是很大,但是,当随着数据量的增加,性能会急剧下降. 小宝鸽试了一下,2.5万数据单表中,无索引:200ms-700ms,添加索引后10ms-15ms,使用redis缓存1ms-7ms,如果数据量更大的时候,索引效果将会更加明显.更甚者,多表查询. 索引原理

数据库查询优化-添加索引

在数据库中,我们通过创建索引可以大大提高查询的速度,一个好的索引可以另SQL的查询更加效率.而一个错误的索引不仅带不来效率的提高,甚至会带来额外的系统开销 索引的基本操作创建索引建表时创建索引 建表的时候指定 CREATE TABLE user(       ID INT NOT NULL,        username VARCHAR(16) NOT NULL,        INDEX [indexName] (username(length)));12345CREATE创建索引 为已有的

索引和查询优化

索引和查询优化 添加索引的三种方法 一.Alter table 表名 add 键类型 (列列表) 键类型:primary key/unique key/fulltext index/index(普通索引可以在index后接索引名) 二.建表时在列名 类型 后加索引类型 三.建表时在所有列名后面加索引类型(列列表) (全文索引是为了解决like%这种效率低的查询方式提出的查询优化) 索引的原理 索引的存在就是为了加快查询速度的.每个行记录按照主键大小顺序排列在一个页中,形成一个单链表,每个页都有一

MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术

逻辑查询优化包括的技术 1)子查询优化  2)视图重写  3)等价谓词重写  4)条件简化  5)外连接消除  6)嵌套连接消除  7)连接消除  8)语义优化 9)非SPJ优化 一.子查询优化 1. 什么是子查询:当一个查询是另一个查询的子部分时,称之为子查询. 2. 查询的子部分,包含的情况: a) 目标列位置:子查询如果位于目标列,则只能是标量子查询,否则数据库可能返回类似“错误:子查询只能返回一个字段 ( [Err] 1242 - Subquery returns more than 1

数据库索引总结

一.为什么要创建索引呢(优点)? 这是因为,创建索引可以大大提高系统的性能. 第一,   通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性. 第二,   可以大大加快数据的检索速度,这也是创建索引的最主要的原因. 第三,   可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义. 第四,   在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间. 第五,   通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能. 二.建立方向索引的不利因

Sql Server系列:索引基础

1. 索引概念 索引用于快速查找在某个列中某个特定值的行,不使用索引,数据库必须从第1条记录开始读完整个表,知道找出需要的行.表越大,查询数据所花费的时间越多.如果表中查询的列有索引,数据库能快速到达一个位置去查找数据,而不必遍历所有数据. 索引是一个单独的.存储在磁盘上的数据库结构,包含对数据表里所有记录的引用指针.使用索引用于快速找出一个或多个列中有特定值的行,对相关列使用索引是降低查询操作时间的最佳途径.索引包含由表或试图中的一列或多列生成的键. 索引的优点: ◊ 通过创建唯一索引,可以保

索引的优点和缺点

一.为什么要创建索引呢(优点)?这是因为,创建索引可以大大提高系统的性能.第一,   通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性.第二,   可以大大加快数据的检索速度,这也是创建索引的最主要的原因.第三,   可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义.第四,   在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间.第五,   通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能. 二.建立方向索引的不利因素(缺点)也

SQL语句-创建索引

  语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100GO USE 库名GOIF EXISTS (SELECT * FROM SYSINDEXES WHERE NAME='IX_TEST_TNAME')--检测是否已经存在IX_TEST_TNAME索引DROP INDEX TEST.IX_TEST_TNAME--如果存在则删除 --创建索引CREATE NONCLUSTERED INDEX IX_TEST_TNAME