我有这个查询,它可以进行性能调整,因为运行时间超过4-5小时。
public function percent($num_amount, $num_total)
{
if($num_total > 0){
$count1 = $num_amount / $num_total;
$count2 = $count1 * 100;
$count = round($count2);
return $count;
}else{
return 0; // or whatever you want
}
}
我在这里发布原始查询,该查询在过程中被称为游标。
解释在需要时间的域上进行查询的计划是 -
explain plan for SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4)
INDEX(ssp sub_svc_parm_ix2) */
SUB_SVC_ID
FROM SUB_SVC_PARM ssp
WHERE PARM_ID = GET_PARM_ID('net_ppv_credit_limit', GET_CLASS_ID('SubSvcSpec'), GET_SVCID('smp_cpe_cas'))
AND VAL <> '140.00'
AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */
1
FROM SUB_SVC ss
WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID
AND ss.SUB_SVC_STATUS_ID NOT IN (FN_GET_STATUS_ID('SubSvcSpec', 'deleted'),
FN_GET_STATUS_ID('SubSvcSpec', 'inactive'),
FN_GET_STATUS_ID('SubSvcSpec', 'add_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'activation_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'courtesy_block_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'mso_block_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'delete_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'deactivation_in_progress'),
FN_GET_STATUS_ID('SubSvcSpec', 'change_in_progress')));
在这两个表上构建的索引是---
SUB_SVC TABLE
Plan hash value: 4290343623
---------------------------------------------------------------------------- -----------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------- ------------------------------
| 0 | SELECT STATEMENT | | 1802K| 56M| | 528K (1)|730:11:02 |
|* 1 | HASH JOIN RIGHT SEMI | | 1802K| 56M| 37M| 528K (1)|730:11:02 |
|* 2 | TABLE ACCESS FULL | SUB_SVC | 1763K| 16M| | 311K (1)|430:15:33 |
| 3 | TABLE ACCESS BY INDEX ROWID| SUB_SVC_PARM | 2394K| 52M| | 209K (0)|288:56:00 |
|* 4 | INDEX RANGE SCAN | SUB_SVC_PARM_IX2 | 2394K| | | 1519 (0)| 02:05:59 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("SS"."SUB_SVC_ID"="SSP"."SUB_SVC_ID")
2 - filter("SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deleted') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','inactive') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','add_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','activation_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','courtesy_block_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','mso_block_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','delete_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','deactivation_in_progress') AND
"SS"."SUB_SVC_STATUS_ID"<>"FN_GET_STATUS_ID"('SubSvcSpec','change_in_progress'))
4 - access("PARM_ID"="GET_PARM_ID"('net_ppv_credit_limit',"GET_CLASS_ID"('SubSvcSpec'),"GET_SV
CID"('smp_cpe_cas')))
filter("VAL"<>'140.00')
SUB_SVC_PARM表
index_name coulmn_name
----------- ------------
SUB_SVC_PK sub_svc_id
SUB_SVC_IX4 PARENT_SUB_SVC_ID
SUB_SVC_IX5 EXTERNAL_KEY
SUB_SVC_IX6 SUB_SVC_IX6
为SUB_SVC_PARM表创建表语法
index_name coulmn_name
----------- ------------
SUB_SVC_PARM_PK SUB_SVC_ID, PARM_ID
SUB_SVC_PARM_IX2 PARM_ID, VAL
同时我正在尝试对调用where子句的函数使用WITH子句,但是在过程中函数被捕获在常量变量中,然后在查询中使用!
我的数据库是:Oracle Database 11g企业版11.2.0.2.0版 - 64位生产
如果需要,请询问更多信息。 谢谢
编辑:此程序正在使用查询,而不是由我编写的! 我认为这个程序本身需要调整而不是查询
请建议
CREATE TABLE "SMPHOMCM"."SUB_SVC_PARM"
( "SUB_SVC_ID" NUMBER(12,0) NOT NULL ENABLE,
"PARM_ID" NUMBER(12,0) NOT NULL ENABLE,
"VAL" VARCHAR2(2000 BYTE) NOT NULL ENABLE,
CONSTRAINT "SUB_SVC_PARM_PK" PRIMARY KEY ("SUB_SVC_ID", "PARM_ID")
USING INDEX)
CREATE TABLE SYNTAX FOR SUB_SVC TABLE
CREATE TABLE "SMPHOMCM"."SUB_SVC"
( "SUB_SVC_ID" NUMBER(12,0) NOT NULL ENABLE,
"SUB_ID" NUMBER(12,0) NOT NULL ENABLE,
"START_DT" DATE NOT NULL ENABLE,
"EXTERNAL_KEY" VARCHAR2(100 BYTE) NOT NULL ENABLE,
"SAMP_VER" NUMBER(9,0) NOT NULL ENABLE,
"SUB_SVC_STATUS_ID" NUMBER(12,0) NOT NULL ENABLE,
"CREATED_DTM" DATE NOT NULL ENABLE,
"CREATED_BY" VARCHAR2(30 BYTE) NOT NULL ENABLE,
"END_DT" DATE,
"PURCHASE_DT" DATE,
"PARENT_SUB_SVC_ID" NUMBER(12,0),
"PRE_STATUS_ID" NUMBER(12,0),
"MODIFIED_DTM" DATE,
"MODIFIED_BY" VARCHAR2(30 BYTE),
"SVC_ID" NUMBER(12,0),
CONSTRAINT "SUB_SVC_PK" PRIMARY KEY ("SUB_SVC_ID")
USING INDEX)
创建两个指数后的解释计划 -
CREATE OR REPLACE PROCEDURE PPV_CREDIT_LIMIT(p_exid NUMBER)
IS
-- Flag 'N' is null
TYPE tab_sub_svc_id IS TABLE OF SUB_SVC_PARM.SUB_SVC_ID%TYPE INDEX BY PLS_INTEGER;
rs_sub_svc_id tab_sub_svc_id;
c_class_SubSvcSpec constant pls_integer := GET_CLASS_ID('SubSvcSpec');
c_svc_smp_cpe_cas constant pls_integer := GET_SVCID('smp_cpe_cas');
c_parm_net_ppv_credit_limit constant pls_integer := GET_PARM_ID('net_ppv_credit_limit', c_class_SubSvcSpec, c_svc_smp_cpe_cas);
c_deleted constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'deleted');
c_inactive constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'inactive');
c_add_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'add_in_progress');
c_activation_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'activation_in_progress');
c_courtesy_block_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'courtesy_block_in_progress');
c_mso_block_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'mso_block_in_progress');
c_delete_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'delete_in_progress');
c_deactivation_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'deactivation_in_progress');
c_change_in_progress constant pls_integer := FN_GET_STATUS_ID('SubSvcSpec', 'change_in_progress');
c_ppv_credit_limit constant varchar2(6) := '140.00';
-- Added for net_creditthreshold parm
c_parm_ppv_credit_threshold constant pls_integer := GET_PARM_ID('net_ppv_creditthreshold', c_class_SubSvcSpec, c_svc_smp_cpe_cas);
c_ppv_credit_threshold constant varchar2(6) := '80.00';
ilimit CONSTANT PLS_INTEGER := 1000;
iCheck CONSTANT PLS_INTEGER := 10;
l_total_recs PLS_INTEGER;
l_rec_cnt PLS_INTEGER;
l_curr_cnt PLS_INTEGER := 0;
l_batch PLS_INTEGER := 0;
v_stop_flag CHAR(1) := 'N';
cursor curPPV_CL IS
SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4)
INDEX(ssp sub_svc_parm_ix2) */
SUB_SVC_ID
FROM SUB_SVC_PARM ssp
WHERE PARM_ID = c_parm_net_ppv_credit_limit
AND VAL <> '140.00'
AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */
1
FROM SUB_SVC ss
WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID
AND ss.SUB_SVC_STATUS_ID NOT IN (c_deleted,
c_inactive,
c_add_in_progress,
c_activation_in_progress,
c_courtesy_block_in_progress,
c_mso_block_in_progress,
c_delete_in_progress,
c_deactivation_in_progress,
c_change_in_progress));
BEGIN
DBMS_APPLICATION_INFO.set_action (NULL);
DBMS_APPLICATION_INFO.set_module (NULL, NULL);
DBMS_APPLICATION_INFO.set_client_info (NULL);
DBMS_APPLICATION_INFO.set_module (module_name => 'Procedure: PPV_CREDIT_LIMIT',
action_name => 'Counting total updatable records');
SELECT /*+ PARALLEL_INDEX(ssp, sub_svc_parm_ix2, 4)
INDEX(ssp sub_svc_parm_ix2) */
COUNT(SUB_SVC_ID)
INTO l_total_recs
FROM SUB_SVC_PARM ssp
WHERE PARM_ID = c_parm_net_ppv_credit_limit
AND VAL <> '140.00'
AND EXISTS (SELECT /*+ PARALLEL_INDEX(ss, sub_svc_pk, 4) */
1
FROM SUB_SVC ss
WHERE ss.SUB_SVC_ID = ssp.SUB_SVC_ID
AND ss.SUB_SVC_STATUS_ID NOT IN (c_deleted,
c_inactive,
c_add_in_progress,
c_activation_in_progress,
c_courtesy_block_in_progress,
c_mso_block_in_progress,
c_delete_in_progress,
c_deactivation_in_progress,
c_change_in_progress));
DBMS_OUTPUT.PUT_LINE('Total records for updating are : ' || l_total_recs);
OPEN curPPV_CL;
LOOP
FETCH curPPV_CL
BULK COLLECT INTO rs_sub_svc_id limit ilimit;
l_rec_cnt := rs_sub_svc_id.COUNT;
l_curr_cnt := l_curr_cnt + l_rec_cnt;
DBMS_APPLICATION_INFO.set_module (module_name => 'Procedure: PPV_CREDIT_LIMIT',
action_name => 'Updating ' || l_curr_cnt || ' of ' || l_total_recs);
for idx in 1 .. l_rec_cnt
LOOP
UPDATE SUB_SVC_PARM
SET VAL = c_ppv_credit_limit
WHERE SUB_SVC_ID = rs_sub_svc_id(idx)
AND PARM_ID = c_parm_net_ppv_credit_limit;
UPDATE SUB_SVC_PARM
SET VAL = c_ppv_credit_threshold
WHERE SUB_SVC_ID = rs_sub_svc_id(idx)
AND PARM_ID = c_parm_ppv_credit_threshold;
END LOOP;
COMMIT;
l_batch := l_batch + 1;
DBMS_APPLICATION_INFO.set_client_info ('BATCH:' || l_batch * ilimit);
EXIT WHEN l_rec_cnt < ilimit;
IF MOD(l_batch, iCheck) = 0
THEN
SELECT STOP_FLAG
INTO v_stop_flag
FROM DM_PPV_CREDIT_LIMIT
WHERE EXECUTION_ID = p_exid;
END IF;
EXIT WHEN v_stop_flag = 'Y';
END LOOP;
CLOSE curPPV_CL;
DBMS_OUTPUT.PUT_LINE('Have updated records : ' || l_curr_cnt || ' out of total records : ' || l_total_recs );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END PPV_CREDIT_LIMIT;
答案 0 :(得分:-1)
评论时间有点长。
您的查询计划和索引看起来合理。这导致人们怀疑函数调用。
您的数据看起来不是很大。 。 。有几百万行的表。我怀疑这些被称为无数次。来自更传统的编程语言的人通常认为函数是在SQL中编程的好方法;不幸的是,它们会产生很多开销,因为它们可能阻止优化器完成其工作。
那么,你可以将函数声明为DETERMINISTIC
吗?这将有助于优化器编译它们。其次,将值存储在CTE中的NOT IN
列表中,或者更好地存储在带索引的临时表中。为PARM_ID
值做类似的事情。
答案 1 :(得分:-1)
由于只有你要返回的SUB_SVC_ID
,你可以从SUB_SVC匹配的SUB_SVC_PARM或SUB_SVC_PARM的SUB_SVC或两者的连接或交叉点获得它。在任何情况下,优化器都应该达到相同的执行计划,但您仍然可以尝试:
您的查询(使用IN而不是EXISTS,除了增强可读性之外不会改变任何内容):
select sub_svc_id
from sub_svc_parm
where parm_id = get_parm_id(...)
and val <> '140.00'
and sub_svc_id in (select sub_svc_id from sub_svc where sub_svc_status_id not in (...));
备选方案#1:
select sub_svc_id
from sub_svc
where sub_svc_status_id not in (...)
and sub_svc_id in
(select * from sub_svc_parm where parm_id = get_parm_id(...) and val <> '140.00');
备选方案#2:
select sub_svc_id
from sub_svc ss
join sub_svc_parm ssp using (sub_svc_id)
where ss.sub_svc_status_id not in (...)
and ssp.parm_id = get_parm_id(...)
and ssp.val <> '140.00');
备选方案#3:
select sub_svc_id
from sub_svc_parm
where parm_id = get_parm_id(...)
and val <> '140.00'
intersect
select sub_svc_id
from sub_svc
where sub_svc_status_id not in (...));
在任何情况下,索引最好应为:sub_svc_parm(parm_id, val, sub_svc_id)
和sub_svc(sub_svc_status_id, sub_svc_id)
。添加这些可能已经加快了现有查询的速度。
我首先尝试它,没有任何提示,看看优化器为这些查询生成了什么执行计划。然后,您可能希望再次添加并行化提示。