在连接小型和大型表并在小型表上使用where子句时,可以提高查询性能

时间:2013-10-28 05:57:01

标签: join oracle11g query-optimization

我有两张表,一张有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索引。

第一个查询执行速度非常快,但第二个查询非常慢。能不能让我知道需要做些什么才能使第二个运行得更快?

1 个答案:

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