想要在oracle数据库中花费很长时间从select查询处理5000条记录

时间:2013-11-19 15:47:57

标签: sql oracle oracle10g oracle-sqldeveloper database-performance

每次我想要处理5000条记录,如下所示。

我第一次要处理1到5000行的记录。 第二次我想处理5001到10000行的记录。 第三次我想处理从10001到15001行的记录,如明智的

我不想去程序或PL / SQL。我将更改代码中的rnum值以获取5000条记录。

给定查询需要3分钟才能从3个连接表中获取记录。如何减少获取记录的时间。

select * from  (
SELECT to_number(AA.MARK_ID) as MARK_ID, AA.SUPP_ID as supplier_id, CC.supp_nm as SUPPLIER_NAME, CC.supp_typ as supplier_type, 
CC.supp_lock_typ as supplier_lock_type, ROW_NUMBER() OVER (ORDER BY AA.MARK_ID) as rnum 
from TABLE_A AA, TABLE_B BB, TABLE_C CC  
WHERE 
AA.MARK_ID=BB.MARK_ID AND 
AA.SUPP_ID=CC.location_id  AND 
AA.char_id='160' AND  
BB.VALUE_KEY=AA.VALUE_KEY AND 
BB.VALUE_KEY=CC.VALUE_KEY
AND AA.VPR_ID IS NOT NULL) 
where rnum >=10001  and rnum<=15000;

我尝试过以下情况,但没有运气。

  

我已经尝试了/ * + USE_NL(AA BB)* /提示。   我用过的地方存在于哪里。但它花了相同的3分钟来获取记录。

以下是表格详情。

select count(*) from TABLE_B;
-----------------
2275

select count(*) from TABLE_A;
-----------------
2405276

select count(*) from TABLE_C;
-----------------
1269767

我的内部查询总记录的结果是

SELECT count(*) 
from TABLE_A AA, TABLE_B BB, TABLE_C CC  
WHERE 
AA.MARK_ID=BB.MARK_ID AND 
AA.SUPP_ID=CC.location_id  AND 
AA.char_id='160' AND  
BB.VALUE_KEY=AA.VALUE_KEY AND 
BB.VALUE_KEY=CC.VALUE_KEY
AND AA.VPR_ID IS NOT NULL;
-----------------
2027055

条件正确索引的所有已用列。

给定查询的解释表是......

计划哈希值:3726328503

-------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name             | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                  |  2082K|   182M|       | 85175   (1)| 00:17:03 |
|*  1 |  VIEW                      |                  |  2082K|   182M|       | 85175   (1)| 00:17:03 |
|*  2 |   WINDOW SORT PUSHED RANK  |                  |  2082K|   166M|   200M| 85175   (1)| 00:17:03 |
|*  3 |    HASH JOIN               |                  |  2082K|   166M|       | 44550   (1)| 00:08:55 |
|   4 |     TABLE ACCESS FULL      | TABLE_C          |  1640 | 49200 |       |    22   (0)| 00:00:01 |
|*  5 |     HASH JOIN              |                  |  2082K|   107M|    27M| 44516   (1)| 00:08:55 |
|*  6 |      VIEW                  | index$_join$_005 |  1274K|    13M|       |  9790   (1)| 00:01:58 |
|*  7 |       HASH JOIN            |                  |       |       |       |            |          |
|   8 |        INLIST ITERATOR     |                  |       |       |       |            |          |
|*  9 |         INDEX RANGE SCAN   | TABLE_B_IN2      |  1274K|    13M|       |  2371   (2)| 00:00:29 |
|  10 |        INDEX FAST FULL SCAN| TABLE_B_IU1      |  1274K|    13M|       |  4801   (1)| 00:00:58 |
|* 11 |      TABLE ACCESS FULL     | TABLE_A          |  2356K|    96M|       | 27174   (1)| 00:05:27 |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RNUM">=10001 AND "RNUM"<=15000)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "A"."MARK_ID")<=15000)
   3 - access("A"."SUPP_ID"="C"."LOC_ID" AND "A"."VALUE_KEY"="C"."VALUE_KEY")
   5 - access("A"."MARK_ID"="A"."MARK_ID" AND "A"."VALUE_KEY"="A"."VALUE_KEY")
   6 - filter("A"."MARK_CHN_IND"='C' OR "A"."MARK_CHN_IND"='D')
   7 - access(ROWID=ROWID)
   9 - access("A"."MARK_CHN_IND"='C' OR "A"."MARK_CHN_IND"='D')
  11 - filter("A"."CHNL_ID"=160 AND "A"."VPR_ID" IS NOT NULL)

请问有人帮助我调整此查询,因为我正在尝试过去2天吗?

3 个答案:

答案 0 :(得分:2)

每个查询都需要很长时间,因为每个查询都必须加入然后对所有行进行排序。 row_number分析函数只能在读取整个集合时返回结果。这是非常低效的。如果数据集很大,您只需要排序和散列连接一次。

你应该使用5k行的批量获取整个集合一次。或者,如果要保留现有的代码逻辑,可以将结果存储在临时表中,例如:

CREATE TABLE TMP AS <your above query>
CREATE INDEX ON TMP (rnum)

然后通过

替换代码中的查询
SELECT * FROM TMP WHERE rnum BETWEEN :x AND :y

显然,如果你的临时表被定期重用,只需创建一次并在完成后删除(或使用真正的temporary table)。

答案 1 :(得分:0)

TABLE_A中有多少个唯一的MARK_ID值?我认为如果你通过MARK_ID而不是人工行号来限制记录的获取范围,你可能会获得更好的性能,因为后者显然不是可攻击的。当然,您可能无法在每个范围内获得5000行,但我感觉它不如查询性能那么重要。

答案 2 :(得分:0)

首先,给出混淆的表名几乎不可能推断出有关数据分布和表之间关系的任何信息,因此潜在的回答者从一开始就会瘫痪。

但是,如果table_a中的每一行都匹配其他表中的一行,那么您可以通过将排名降​​低到内联视图或公用表表达式来避免某些200Mb临时磁盘空间的使用,这可能会削弱性能。

监视V $ SQL_WORKAREA以检查用于窗口函数的确切空间量,如果仍然过多,请考虑修改内存管理以增加可用的排序区域大小。

类似的东西:

with cte_table_a as (
  SELECT
    to_number(MARK_ID) as MARK_ID,
    SUPP_ID as supplier_id,
    ROW_NUMBER() OVER (ORDER BY MARK_ID) as rnum 
  from
    TABLE_A
  where
    char_id='160' and
    VPR_ID IS NOT NULL)
select ...
from
  cte_table_a aa,
  TABLE_B BB,
  TABLE_C CC  
WHERE 
  aa.rnum      >= 10001          and
  aa.rnum      <= 15000          and
  AA.MARK_ID   =  BB.MARK_ID     AND 
  AA.SUPP_ID   =  CC.location_id AND 
  BB.VALUE_KEY =  AA.VALUE_KEY   AND 
  BB.VALUE_KEY =  CC.VALUE_KEY