我有两张表,一张有2百万条记录(员工),另外一张有大约一千条记录(城市)。我基于id(City_Id)加入表。 City_Id是Cities表的主键,我在Employees表的City_Id列上有一个索引。
我在这些表上运行以下查询
1)SELECT * FROM EMPLOYEES, CITIES WHERE EMPLOYEES.CITY_ID=CITIES.CITY_ID and EMPLOYEES.EMPLOYEE_NAME='XYZ';
2)SELECT * FROM EMPLOYEES, CITIES WHERE EMPLOYEES.CITY_ID=CITIES.CITY_ID and CITIES.CITY_CLASS='ABC';
我还有EMPLOYEES表的EMPLOYEE_NAME和CITIES表的CITY_CLASS索引。
第一个查询执行速度非常快,但第二个查询非常慢。能不能让我知道需要做些什么才能使第二个运行得更快?
答案 0 :(得分:1)
选择正确的指数
让我在这里构建你的架构
CREATE TABLE EMPLOYEES ( EMPLOYEE_NAME VARCHAR2 ( 50 ),
CITY_ID NUMBER ( 2 ),
DUMMYCOL VARCHAR2 ( 100 ) );
CREATE TABLE CITIES ( CITY_CLASS VARCHAR2 ( 10 ),
CITY_ID NUMBER ( 2 ),
DUMMYCOL VARCHAR2 ( 100 ) );
您提到的索引
CREATE INDEX IDX_T1
ON EMPLOYEES ( EMPLOYEE_NAME );
CREATE INDEX IDX_T2
ON CITIES ( CITY_CLASS );
模拟行数
BEGIN
DBMS_STATS.SET_TABLE_STATS ( OWNNAME => 'REALSPIRITUALS',
TABNAME => 'EMPLOYEES',
NUMROWS => 2000000 );
END;
/
BEGIN
DBMS_STATS.SET_TABLE_STATS ( OWNNAME => 'REALSPIRITUALS',
TABNAME => 'CITIES',
NUMROWS => 1000 );
END;
/
尝试第一次查询
SET AUTOTRACE ON
SELECT
*
FROM
EMPLOYEES,
CITIES
WHERE
EMPLOYEES.CITY_ID = CITIES.CITY_ID
AND EMPLOYEES.EMPLOYEE_NAME = 'XYZ';
注意:查询使用IDX_T1进行更快的撤销,并通过索引访问Employees表 因此它更快
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=27 Card=20 K Bytes=3 M)
1 0 HASH JOIN (Cost=27 Card=20 K Bytes=3 M)
2 1 TABLE ACCESS FULL REALSPIRITUALS.CITIES (Cost=21 Card=1 K Bytes=97 K)
3 1 TABLE ACCESS BY INDEX ROWID REALSPIRITUALS.EMPLOYEES (Cost=5 Card=20 K Bytes=1 M)
4 3 INDEX RANGE SCAN REALSPIRITUALS.IDX_T1 (Cost=1 Card=8 K)
Statistics
----------------------------------------------------------
203 recursive calls
0 spare statistic 3
0 gcs messages sent
29 db block gets from cache
0 physical reads direct (lob)
0 queue position update
0 queue single row
0 queue ocp pages
0 HSC OLTP Compressed Blocks
0 HSC IDL Compressed Blocks
0 rows processed
您现在的第二个查询
SET AUTOTRACE ON
SELECT
*
FROM
EMPLOYEES,
CITIES
WHERE
EMPLOYEES.CITY_ID = CITIES.CITY_ID
AND CITIES.CITY_CLASS = 'ABC';
注意:查询使用IDX_T2进行更快速的检索,但Employees表正在进行全表扫描 因此它更慢
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=52 Card=20 K Bytes=3 M)
1 0 HASH JOIN (Cost=52 Card=20 K Bytes=3 M)
2 1 TABLE ACCESS BY INDEX ROWID REALSPIRITUALS.CITIES (Cost=5 Card=10 Bytes=1000)
3 2 INDEX RANGE SCAN REALSPIRITUALS.IDX_T2 (Cost=1 Card=4)
4 1 TABLE ACCESS FULL REALSPIRITUALS.EMPLOYEES (Cost=38 Card=2 M Bytes=190 M)
Statistics
----------------------------------------------------------
0 recursive calls
0 spare statistic 3
0 gcs messages sent
0 db block gets from cache
0 physical reads direct (lob)
0 queue position update
0 queue single row
0 queue ocp pages
0 HSC OLTP Compressed Blocks
0 HSC IDL Compressed Blocks
0 rows processed
现在我要添加一个索引
CREATE INDEX IDX_T3
ON EMPLOYEES ( CITY_ID );
重试第二次查询
SET AUTOTRACE ON
SELECT
*
FROM
EMPLOYEES,
CITIES
WHERE
EMPLOYEES.CITY_ID = CITIES.CITY_ID
AND CITIES.CITY_CLASS = 'ABC';
注意:避免使用FTS,查询使用索引进行检索
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=5 Card=20 K Bytes=3 M)
1 0 NESTED LOOPS
2 1 NESTED LOOPS (Cost=5 Card=20 K Bytes=3 M)
3 2 TABLE ACCESS BY INDEX ROWID REALSPIRITUALS.CITIES (Cost=5 Card=10 Bytes=1000)
4 3 INDEX RANGE SCAN REALSPIRITUALS.IDX_T2 (Cost=1 Card=4)
5 2 INDEX RANGE SCAN REALSPIRITUALS.IDX_T3 (Cost=0 Card=1)
6 1 TABLE ACCESS BY INDEX ROWID REALSPIRITUALS.EMPLOYEES (Cost=0 Card=2 K Bytes=195 K)
Statistics
----------------------------------------------------------
1 recursive calls
0 spare statistic 3
0 gcs messages sent
0 db block gets from cache
0 physical reads direct (lob)
0 queue position update
0 queue single row
0 queue ocp pages
0 HSC OLTP Compressed Blocks
0 HSC IDL Compressed Blocks
0 rows processed
这应该更快:) 一般来说,为了加快查询速度,请始终只针对where子句中使用的列进行索引