如何摆脱oracle中的FULL TABLE SCAN

时间:2016-10-14 10:38:35

标签: oracle performance

我有一个查询,它在做解释计划时给我全表扫描,所以你能告诉我如何摆脱它。

输出:

|*  9 |          INDEX UNIQUE SCAN         | GL_PERIODS_U1        |     1 |       |       |     1   (0)|
|* 10 |         TABLE ACCESS FULL          | GL_PERIODS           |    12 |   372 |       |     6   (0)|
|* 11 |        TABLE ACCESS BY INDEX ROWID | GL_JE_HEADERS        |     1 |    37 |       |   670   (0)|
|* 12 |         INDEX RANGE SCAN           | GL_JE_HEADERS_N2     |  3096 |       |       |    11   (0)|
|* 13 |       TABLE ACCESS BY INDEX ROWID  | GL_JE_BATCHES        |     1 |     8 |       |     2   (0)|
|* 14 |        INDEX UNIQUE SCAN           | GL_JE_BATCHES_U1     |     1 |       |       |     1   (0)|
|* 15 |      INDEX RANGE SCAN              | GL_JE_LINES_U1       |   746 |       |       |     4   (0)|
|  16 |    TABLE ACCESS FULL               | GL_CODE_COMBINATIONS |  1851K|    30M|       | 13023   (1)|

我的查询:

explain plan for 
    select cc.segment1,
           cc.segment2,
           h.currency_code,
           SUM(NVL(l.accounted_dr,0) - NVL(l.accounted_cr,0))
    from   gl_code_combinations cc
          ,gl_je_lines   l
          ,gl_je_headers h
          ,gl_je_batches b
          ,gl_periods    p1  
          ,gl_periods    p2  
    where   cc.code_combination_id = l.code_combination_id
    AND     b.je_batch_id = h.je_batch_id
    AND     b.status = 'P'
    AND     l.je_header_id = h.je_header_id
    AND     h.je_category = 'Revaluation'
    AND     h.period_name     = p1.period_name
    AND    p1.period_set_name = 'Equant Master'
    AND    p2.period_name = 'SEP-16'
    AND    p2.period_set_name = 'Equant Master'
    AND    p1.start_date     <= p2.end_date
    AND    h.set_of_books_id = '1429'
    GROUP BY cc.segment1,
            cc.segment2,
            h.currency_code

请建议

2 个答案:

答案 0 :(得分:1)

我发现您正在使用Oracle电子商务套件数据模型。在该模型中,作为会计期间表(通常是数周或数月)的GL_PERIODS通常相当小。此外,您告诉它您希望每个之前期间到2016年9月,这可能几乎是您的“Equant Master”期间设置的所有期间。根据您定义的其他期间集的数量,您的全表扫描很可能是最佳(最快运行)计划。

正如其他人正确指出的那样,全表扫描不一定比其他访问路径更差或更慢。

要确定您的FTS是否确实存在问题,您可以使用DBMS_XPLAN来确定计划中每个步骤的时间。像这样:

首先,告诉Oracle跟踪会话的计划步骤级别统计信息

alter session set statistics_level = ALL;

确保关闭DBMS_OUTPUT /服务器输出

运行查询以完成(即滚动到结果集的底部)

最后,运行此查询:

SELECT *
FROM   TABLE (DBMS_XPLAN.display_cursor (null, null,
                                         'ALLSTATS LAST'));

输出将告诉您完全为什么您的查询花了这么长时间(如果 花费很长时间)。它比在解释计划中选择所有全表扫描要准确得多。

答案 1 :(得分:0)

首先,您为什么要避免全表扫描?所有全表扫描都不错。

您正在加入同一个表cc.code_combination_id = l.code_combination_id。我不认为有一点可以避免对这些类型的连接进行全表扫描。

为了理解这一点,我创建了测试表和数据。

创建表I1(n号主键,v varchar2(10)); create table I2(n number primary key,v varchar2(10));

和地图表 创建表MAP(n号主键,i1号引用I1(n), i2号参考I2(n));

我在地图表上创建了索引。 在地图上创建索引map_index_i1(i1); 在地图上创建索引map_index_i2(i2);

以下是我插入的示例数据。

SQL&GT;从i1中选择*;

     N V
     1 ONE
     2 TWO
     5 FIVE

SQL&GT;从i2中选择*;

     N V
     3 THREE
     4 FOUR
     5 FIVE

SQL&GT; select * from map;

     N         I1         I2
     1          1          3
     2          1          4
     5          5          5

我收集了统计数据。然后,我执行了使用映射表中的I1和I2的查询。

explain plan for
select map.n,i1.v 
from i1,map
where map.i2 = map.i1
and i1.n=5 

请记住,我们在地图表的I1和I2上有索引。我认为优化器可能会使用索引,但不幸的是它并没有。

Full table scan

因为条件map.i2 = map.i1意味着将地图表的I2列的每条记录与I1进行比较。

接下来,我在where条件中使用了一个索引列,现在它选择了索引。

explain plan for
select map.n,i1.v
from i1,map
where map.i2 = map.i1
and i1.n=5
and map.i1=5 

Index scan

查看ASK Tom的页面进行全表扫描。不幸的是,我不能粘贴源链接,因为我的声誉不到10!