【问题标题】:Improve query performance when joining a small and a large table and using a where clause on the small table连接小表和大表并在小表上使用 where 子句时提高查询性能
【发布时间】:2013-11-06 19:47:49
【问题描述】:

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

第一个查询执行得非常快,但第二个查询执行得非常慢。能否请您告诉我需要做什么才能使第二个运行得更快?

【问题讨论】:

  • 请将两个查询的执行计划附加到您的问题中。
  • EMPLOYEES.CITY_ID 上有索引吗?如果没有,则创建它,并检查查询速度。

标签: join oracle11g query-optimization


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2017-10-14
    • 2013-02-16
    相关资源
    最近更新 更多