循环开始如下:
FOR z in 1 .. val LOOP --val is some variable
select add_months(p_in_usageMonth, - (z - 1))
INTO v_usage_month
from dual; ---simple select
select count(*)
into n_invoice_exists
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description = 'SUCCESS')
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
and NVL(engine_serial_number, '%') like NVL(p_in_esn, '%')
and inv.billing_invoice_type not in ('C', 'M', 'R');
IF n_invoice_exists = 0 THEN
- fmo_op2_contract表中的索引 - --UNIQUE- ONPOINT_CONTRACT_NUMBER,CONTRACT_SEQ_ID,CONTRACT_NAME --NORMAL- FIN_SSO,CONTRACT_SEQ_ID,CONTRACT_SEQ_ID
IF upper(p_in_billingType) = 'POPULAR' or
upper(p_in_billingType) = 'RESTORED' THEN
SELECT UPPER(nvl(usage_type_popular,
fmo_op2_contract.usage_type_restored)),
UPPER(nvl(fmo_op2_contract.usage_category_popular,
fmo_op2_contract.usage_category_restored))
INTO v_usage_type, v_usage_category
FROM fmo_op2_contract
WHERE contract_seq_id = p_in_contractId;
IF v_usage_type = 'ENGINE' THEN
if p_in_esn is null then
v_engine_serial_number := '%';
else
v_engine_serial_number := p_in_esn;
end if;
- fmo_op2_invoice的索引 --UNIQUE-INVOICE_NUM
select count(*)
into v_tot
from (select distinct invoice_num
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description =
'SUCCESS')
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
and NVL(engine_serial_number, '%') like
v_engine_serial_number);
IF v_tot > 0 THEN
select distinct invoice_num
INTO v_inv_num
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description = 'SUCCESS')
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
and NVL(engine_serial_number, '%') like
v_engine_serial_number;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
--if inv present
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_engine_usage_factors
WHERE usage_month = v_usage_month
and contract_seq_id = p_in_contractId;
DELETE FROM fmo_op2_engine_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
AND upper(usage_category)<>'BASL';
---在循环中调用另一个过程。 save_engine_utilization_prc(p_in_contractId, p_in_billingType, v_usage_month, p_in_esn, p_in_util_data_list, p_in_fact_avg_list, p_in_login_id, VAL, Z, p_out_success_status, p_out_esn_check_fails, p_out_error);
SELECT v_i - 1 INTO p_out_count FROM DUAL;
ELSIF v_usage_type = 'FLEET' THEN
select count(*)
into v_tot
from (select distinct invoice_num
FROM fmo_op2_fleet_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null
and contract_seq_id = p_in_contractId);
IF v_tot > 0 THEN
-- tot invoice
select distinct invoice_num
INTO v_inv_num
FROM fmo_op2_fleet_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y'
)
and usage_month = v_usage_month
and invoice_num is not null
and contract_seq_id = p_in_contractId;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_fleet_usage_factors
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month;
DELETE FROM fmo_op2_fleet_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
and invoice_num is null;
---another procedure call
save_fleet_utilization_prc(p_in_contractId,
p_in_billingType,
v_usage_month,
p_in_esn,
p_in_util_data_list,
p_in_fact_avg_list,
p_in_login_id,
val,
z,
p_out_success_status,
p_out_esn_not_exists,
p_out_esn_check_fails,
p_out_error);
ELSIF v_usage_type = 'TAIL' THEN
select count(*)
into v_tot
from (select distinct invoice_num
FROM fmo_op2_tail_usage
WHERE trim(tail_number) in
(select tail_number
from fmo_op2_engine_master e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null);
IF v_tot > 0 THEN
-- tot invoice
select distinct invoice_num
INTO v_inv_num
FROM fmo_op2_tail_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
--if inv present
- fmo_op2_status上的索引 --STATUS_SEQ_ID -UNIQUE
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_tail_usage_factors
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month;
DELETE FROM fmo_op2_tail_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
and invoice_num is null;
save_tail_utilization_prc(p_in_contractId,
p_in_billingType,
v_usage_month,
p_in_esn,
p_in_util_data_list,
p_in_fact_avg_list,
p_in_login_id,
val,
z,
p_out_success_status,
p_out_esn_not_exists,
p_out_esn_check_fails,
p_out_error);
SELECT v_i - 1 INTO p_out_count FROM DUAL;
SELECT v_j - 1 INTO p_out_check_fail_count FROM DUAL;
END IF;
END IF;
END IF;
END LOOP;
- 每张表的记录数约为1500。 此循环执行700次并占用大量时间。 我该如何优化呢?
答案 0 :(得分:0)
有一些问题,我将它们标记为内联: 首先要注意的是,你正在使用第二个查询的核心很多,也许你应该考虑对一个更大的&#34;进行相同的查询。 结果集,但你会&#34;计算&#34;它一次。或者更快,请参阅内联评论
FOR z in 1 .. val LOOP --val is some variable
select add_months(p_in_usageMonth, - (z - 1))
INTO v_usage_month
from dual; ---simple select
select count(*)
into n_invoice_exists
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
--issue No.1: remove that query from here and put it into a WITH or a subselect for a join
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description = 'SUCCESS')
--issue No.2.: remove it too like above, using a left outer and an IS NULL condition in the where
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
--issue No.3.: replace like to = , it's pointless to search with like and more expensive
and NVL(engine_serial_number, '%') like NVL(p_in_esn, '%')
and inv.billing_invoice_type not in ('C', 'M', 'R');
IF n_invoice_exists = 0 THEN
IF upper(p_in_billingType) = 'POPULAR' or
upper(p_in_billingType) = 'RESTORED' THEN
SELECT UPPER(nvl(usage_type_popular,
fmo_op2_contract.usage_type_restored)),
UPPER(nvl(fmo_op2_contract.usage_category_popular,
fmo_op2_contract.usage_category_restored))
INTO v_usage_type, v_usage_category
FROM fmo_op2_contract
WHERE contract_seq_id = p_in_contractId;
IF v_usage_type = 'ENGINE' THEN
if p_in_esn is null then
v_engine_serial_number := '%';
else
v_engine_serial_number := p_in_esn;
end if;
select count(*)
into v_tot
from (
--issue No.4.: replace distinct to "group by", 'cause group by using hash instead of expensive sorting of the distinct. And the rest issues are the same like above
select distinct invoice_num
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description =
'SUCCESS')
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
and NVL(engine_serial_number, '%') like
v_engine_serial_number);
IF v_tot > 0 THEN
--issue No.5.: see above
select distinct invoice_num
INTO v_inv_num
from fmo_op2_invoice inv
where inv.usage_month = v_usage_month
and contract_seq_id = p_in_contractId
and inv.invoice_status_id =
(select status_seq_id
from fmo_op2_status
where status_type = 'INVOICE'
and fmo_op2_status.status_description = 'SUCCESS')
and invoice_num not in
(select NVL(rev.cancelled_invoice_number, 'X')
from fmo_op2_invoice rev)
and NVL(engine_serial_number, '%') like
v_engine_serial_number;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
--if inv present
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_engine_usage_factors
WHERE usage_month = v_usage_month
and contract_seq_id = p_in_contractId;
DELETE FROM fmo_op2_engine_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
AND upper(usage_category)<>'BASL';
save_engine_utilization_prc(p_in_contractId, p_in_billingType, v_usage_month, p_in_esn, p_in_util_data_list, p_in_fact_avg_list, p_in_login_id, val, z, p_out_success_status, p_out_esn_check_fails, p_out_error);
--issue No.6.: avoiding unnecessary context switching, replace that stmt to a simple p_out_count := v_i -1 ;
SELECT v_i - 1 INTO p_out_count FROM DUAL;
ELSIF v_usage_type = 'FLEET' THEN
--issue No.7.: just like above
select count(*)
into v_tot
from (select distinct invoice_num
FROM fmo_op2_fleet_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null
and contract_seq_id = p_in_contractId);
IF v_tot > 0 THEN
-- tot invoice
--issue No.8.: same
select distinct invoice_num
INTO v_inv_num
FROM fmo_op2_fleet_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y'
)
and usage_month = v_usage_month
and invoice_num is not null
and contract_seq_id = p_in_contractId;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_fleet_usage_factors
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month;
DELETE FROM fmo_op2_fleet_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
and invoice_num is null;
save_fleet_utilization_prc(p_in_contractId,
p_in_billingType,
v_usage_month,
p_in_esn,
p_in_util_data_list,
p_in_fact_avg_list,
p_in_login_id,
val,
z,
p_out_success_status,
p_out_esn_not_exists,
p_out_esn_check_fails,
p_out_error);
ELSIF v_usage_type = 'TAIL' THEN
--issue No.9.: same
select count(*)
into v_tot
from (select distinct invoice_num
FROM fmo_op2_tail_usage
WHERE trim(tail_number) in
(select tail_number
from fmo_op2_engine_master e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null);
IF v_tot > 0 THEN
-- tot invoice
--issue No.10.: same
select distinct invoice_num
INTO v_inv_num
FROM fmo_op2_tail_usage
WHERE trim(subfleet_id) in
(select subfleet_id
from fmo_op2_fleet e
where e.contract_seq_id = p_in_contractId
and e.valid_ind = 'Y')
and usage_month = v_usage_month
and invoice_num is not null;
SELECT COUNT(*)
INTO v_inv_exists
FROM (SELECT *
from fmo_op2_invoice
WHERE invoice_num = v_inv_num);
IF v_inv_exists > 0 THEN
--if inv present
SELECT COUNT(*)
INTO v_cancelled
FROM (SELECT *
FROM fmo_op2_invoice a, fmo_op2_status b
WHERE a.cancelled_invoice_number = v_inv_num
AND a.invoice_status_id = b.status_seq_id
AND b.status_code = 'S');
IF v_cancelled = 0 THEN
RAISE ex_custom;
END IF;
END IF;
END IF;
DELETE FROM fmo_op2_tail_usage_factors
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month;
DELETE FROM fmo_op2_tail_usage
WHERE contract_seq_id = p_in_contractId
and usage_month = v_usage_month
and invoice_num is null;
save_tail_utilization_prc(p_in_contractId,
p_in_billingType,
v_usage_month,
p_in_esn,
p_in_util_data_list,
p_in_fact_avg_list,
p_in_login_id,
val,
z,
p_out_success_status,
p_out_esn_not_exists,
p_out_esn_check_fails,
p_out_error);
----issue No.11.: avoid contextswitching
SELECT v_i - 1 INTO p_out_count FROM DUAL;
SELECT v_j - 1 INTO p_out_check_fail_count FROM DUAL;
END IF;
END IF;
END IF;
END LOOP;
并持续到最后,我会检查DELETE stms的exec.time。