想要从选择查询中处理 5000 条记录在 oracle 数据库中需要很长时间
Posted
技术标签:
【中文标题】想要从选择查询中处理 5000 条记录在 oracle 数据库中需要很长时间【英文标题】:Want to process 5000 records from the select query is taking long time in oracle database 【发布时间】:2013-11-19 15:47:56 【问题描述】:每次我想处理 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) */ 提示。 我使用存在于where条件。但获取记录同样需要 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
where条件中所有使用的列都被正确索引了。
给定查询的解释表是...
计划哈希值: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 天开始?
【问题讨论】:
为您的索引命名,因为并非所有索引都已使用,因此使用 FTS。尝试并行提示?试图强制指数低谷提示? (考虑到根据 where 子句对表进行索引) 您想要索引名称吗?我对 oracle 提示一无所知。对于并行使用,我们是否需要更改表中的任何内容 什么都没有,只使用select /*+ parallel (table,N) cols from table;
如果这不起作用去alter session 以启用并行
很抱歉在这里再次问你,我有 3 个表,我必须在并行提示中使用哪个表。表数较高或表数较低,否则需要提及所有表,例如 /*+ parallel (table A, table_b,table_c,16) ?你能建议我这个吗..
在痛点上使用它。根据您的计划,我建议在表 a 和表 c 上使用它
【参考方案1】:
每个查询都需要很长时间,因为每个查询都必须连接然后对所有行进行排序。 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)。
【讨论】:
非常感谢文森特!【参考方案2】:您在 TABLE_A 中有多少个唯一的 MARK_ID 值?我认为如果您通过 MARK_ID 而不是人工行号来限制获取的记录范围,您可能会获得更好的性能,因为后者显然是不可分割的。诚然,您可能无法在每个范围内准确获得 5000 行,但我觉得它不如查询性能重要。
【讨论】:
【参考方案3】:首先,给出混淆的表名使得几乎不可能推断出有关表之间的数据分布和关系的任何信息,因此潜在的回答者从一开始就被削弱了。
但是,如果 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
【讨论】:
以上是关于想要从选择查询中处理 5000 条记录在 oracle 数据库中需要很长时间的主要内容,如果未能解决你的问题,请参考以下文章