0

我有两张表,一张有 200 万条记录(员工),另一张有大约一千条记录(城市)。我正在加入基于 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 上有索引。

第一个查询执行得非常快,但第二个查询执行得非常慢。你能告诉我需要做什么才能让第二个跑得更快吗?

4

1 回答 1

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 进行更快的检索,并通过索引访问员工表,因此速度更快

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 以加快检索速度,但员工表正在进行全表扫描,因此速度较慢

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 子句中使用的列进行索引

于 2013-10-28T16:23:43.473 回答