2011-09-01 164 views
0

我有一个需要太多的查询。 它运行一个10g的oracle实例。 TABLE_A有30.000.000行。 TABLE_B有300.000行。Oracle排序嵌套查询和rownum

SELECT A.F1, A.F2, B.F1 
    FROM ( SELECT A.F1, A.F2, B.F1 
      FROM TABLE_A A LEFT JOIN TABLE_B B ON A.ID_B = B.ID_B 
      WHERE A.F3 = ? AND A.F4 = ? 
     ORDER BY B.F1) 
WHERE ROWNUM < 100 

我试图创建一个视图:

CREATE VIEW TABLE_B_SORTED AS SELECT * FROM TABLE_B ORDER BY F1 

修改查询一样,

SELECT A.F1, A.F2, B.F1 
    FROM ( SELECT A.F1, A.F2, B.F1 
      FROM TABLE_A A LEFT JOIN TABLE_B_SORTED B ON A.ID_B = B.ID_B 
      WHERE A.F3 = ? AND A.F4 = ? 
     ) 
WHERE ROWNUM < 100 

但该命令没有manteined。

我也试着修改查询以这种方式

SELECT A.F1, A.F2, T.F1 
    FROM ( SELECT A.F1, A.F2, T.F1 
      FROM TABLE_A A LEFT JOIN (SELECT * FROM TABLE_B B ORDER BY B.F1) T ON A.ID_B = T.ID_B 
      WHERE A.F3 = ? AND A.F4 = ? 
     ) 
WHERE ROWNUM < 100 

但该命令没有manteined。

有什么建议吗?

Plan 
SELECT STATEMENT ALL_ROWSCost: 8.943 Bytes: 2.871 Cardinality: 99       
    7 COUNT STOPKEY      
     6 VIEW MY_SCHEMA. Cost: 8.943 Bytes: 146.247 Cardinality: 5.043     
      5 SORT ORDER BY STOPKEY Cost: 8.943 Bytes: 226.935 Cardinality: 5.043    
       4 HASH JOIN OUTER Cost: 8.881 Bytes: 226.935 Cardinality: 5.043   
        2 TABLE ACCESS BY INDEX ROWID TABLE TABLE_A Cost: 8.117 Bytes: 172.725 Cardinality: 4.935  
         1 INDEX RANGE SCAN INDEX I_TABLE_A Cost: 27 Cardinality: 10.166 
        3 TABLE ACCESS FULL TABLE TABLE_B Cost: 758 Bytes: 2.791.520 Cardinality: 279.152 
+1

您可以发布此查询生成的解释计划吗? – Ollie

+0

我猜这个查询需要这么长时间的原因是你排序在一个左连接的列。因此,该列上的索引将无济于事,因为排序还必须包含由连接不成功导致的行(导致该列中为NULL值)。一个左连接是否真的有必要,还是一个正确的连接呢?列B.F1是否可以为空? – Codo

+0

@Codo:不幸的是B.F1字段可以为空。 – GAS

回答

0

您应该创建也许如果您的查询需要太多的时间创建b.f1上升的指数。

此外,如果您正在执行LEFT JOIN,这意味着您可能在B中有NULL值。您是否希望它们首先或最后?

也许你应该做的更好:

SELECT /*+ first_rows_100 */ -- do not hesitate to use Oracle hints! 
      a.f1, a.f2, b.f1 
    FROM table_b b 
    INNER JOIN table_a a 
     ON a.id_b = b.id_b 
    WHERE a.f3 = ? and a.f4 = ? 
    ORDER BY b.f1 ASC 

此外,订购加入源完全useles(第二和第三个查询)。 JOINing从不保证结果行保持它们在源表中找到的顺序。

+0

似乎并没有使用/ * + first_rows_100 * /阻止检索超过100行。通过执行查询它需要相同的时间。 我确实执行了一个LEFT JOIN,我可以在TABLE_B中有空值。 我会尝试在TABLE_B上放置一个排序后的索引。 – GAS

+0

排序后的索引不起作用! – GAS

+0

@GAS:你对表格a和b有什么指标?似乎表B上的TABLE ACCESS FULL可以跳过,如果id_b被索引在该表上。 – Benoit