前一章描述了索引的机构,以及引起索引性能差的原因。在接下来的几章里面,我将会展示怎样发现以及避免SQL语句中的各种问题。我们将从where子句开始。
where子句定义了SQL的搜索条件,这个就是索引起作用的最重要的地方:快速查询数据。尽管where子句对性能有着很大的影响,它经常被草草提及,导致数据库经常需要扫描大量的索引。所以:一个书写差劲的where子句是缓慢查询的首要原因。
这一章阐述了不同的操作会影响索引的使用方式以及怎样保障一个索引尽可能多地服务于多种查询。最后一节记录了一些常见的错误,以及告诉大家怎样获得更好的性能。
等号
等号是最常见也是最频繁使用的SQL操作符。索引错误进而影响性能是非常常见的。在where子句中结合多种条件,特别容易出现(性能低下)。
这一节告诉大家怎么样验证索引的使用,以及联合索引怎样能优化符合条件。为了增进理解,我们将分析一个由第一章提到的问题引起的运行缓慢的查询。
我们从最简单也最常见的where子句开始:主键查询。本章中所用的表的定义如下:
CREATE TABLE employees (
employee_id NUMBER NOT NULL,
first_name VARCHAR2(1000) NOT NULL,
last_name VARCHAR2(1000) NOT NULL,
date_of_birth DATE NOT NULL,
phone_number VARCHAR2(1000) NOT NULL,
CONSTRAINT employees_pk PRIMARY KEY (employee_id)
);
数据库会自动为主键创建索引。也就是说,在EMPLOYEE_ID这一列会有一个索引,即使没有CRETE INDEX语句。
下面这条查询语句用主键来获取雇员的名字:
SELECT first_name, last_name
FROM employees
WHERE employee_id = 123
因为主键约束保证了EMPLOYEE_ID的唯一行,所以where子句是不会匹配到多行记录的。数据库没有必要沿着索引叶子节点链来遍历,只需要遍历索引树就行了。我们可以用查询计划来进行验证:
|Id |Operation | Name | Rows | Cost | --------------------------------------------------------------- | 0 |SELECT STATEMENT | | 1 | 2 | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 1 | 2 | |*2 | INDEX UNIQUE SCAN | EMPLOYEES_PK | 1 | 1 | --------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID"=123)
在访问索引之后,数据库需要做额外的一步来从表里获取查询的数据,使用的方式是TABLE ACCESS BY INDEX ROWID。这个操作就变成了性能的瓶颈,就像前一张里面解释的,不过INDEX UNIQUE SCAN 是没有这样的风险的,因为不会有多于一次的表访问。也就是说, INDEX UNIQUE SCAN 不会是造成查询缓慢的原因。