我想处理大量记录,并且我正在使用批量收集指令将数据提取到记录表中。但是,我确信有一种更适当的方法可以实现我所寻找的目标。这是代码:
FUNCTION GET_STORE_ITEMS(I_store IN STORE.STORE%TYPE,
I_item_status IN WIN_STORE.STATUS%TYPE,
----------- output ------------
O_item_data OUT NB_TAB_ITEM_DETAIL,
----------- error -------------
O_error_message OUT VARCHAR2)
RETURN BOOLEAN IS
-- ----------------------------------
-- VARIABLES --
-- ----------------------------------
L_program VARCHAR2(100) := 'NB_ITEM_INFO_SQL.GET_ITEM_DETAIL';
L_error_message VARCHAR2(500) := '';
--
-- ----------------------------------
-- CURSORS --
-- ----------------------------------
-- 003 begin
CURSOR C_get_info IS
-- #004 - begin
SELECT NB_REC_ITEM_DETAIL(sku, desc_up, system_ind, status, division, div_name, group_no, group_name,
dept, dept_name, class, class_name, subclass, sub_name, nb_var_weight,
(SELECT upc as primary_ean
FROM upc_ean u
WHERE u.sku = tab.sku
AND u.primary_upc_ind = 'Y'
AND rownum = 1),
CAST( multiset(SELECT u.upc
FROM upc_ean u
WHERE u.sku = tab.sku
AND u.primary_upc_ind <> 'Y')
AS NB_TAB_ITEM_EAN )
)
FROM (SELECT info.sku,
info.desc_up,
info.nb_var_weight,
info.system_ind,
info.status,
div.division,
div.div_name,
c.group_no,
b.group_name,
info.dept,
c.dept_name,
info.class,
a.class_name,
info.subclass,
e.sub_name
FROM (SELECT w.store,
w.sku,
nvl(wa.nb_var_weight, 'N') nb_var_weight,
w.status,
ts.desc_up,
ts.system_ind,
ts.dept,
ts.class,
ts.subclass
FROM win_store w,
win_attributes wa,
desc_look ts,
deps d
WHERE w.sku = wa.sku
AND w.store = I_store
AND wa.sku = ts.sku
-- AND (w.status = I_item_status OR I_item_status IS NULL)
AND d.dept = ts.dept
UNION ALL
SELECT st.store,
st.sku,
'N' nb_var_weight,
st.status,
ts.desc_up,
ts.system_ind,
ts.dept,
ts.class,
ts.subclass
FROM rag_skus_st st,
desc_look ts,
deps d
WHERE st.store = I_store
AND ts.sku = st.sku
-- AND (st.status = I_item_status OR I_item_status IS NULL)
AND d.dept = ts.dept
UNION ALL
SELECT ps.store,
ps.pack_no,
'N' nb_var_weight,
ps.status,
ts.desc_up,
ts.system_ind,
ts.dept,
ts.class,
ts.subclass
FROM packstore ps,
desc_look ts,
deps d
WHERE ps.store = I_store
AND ps.pack_no = ts.sku
-- AND (ps.status = I_item_status OR I_item_status IS NULL)
AND d.dept = ts.dept
)info,
deps c,
groups b,
division div,
class a,
subclass e
WHERE c.dept = info.dept
AND b.group_no = c.group_no
AND div.division = b.division
AND a.dept = info.dept
AND a.class = info.class
AND e.dept = info.dept
AND e.class = info.class
AND e.subclass = info.subclass
) tab;
--
BEGIN
--
-- Instantiate output structure object.
--
O_item_data := NB_TAB_ITEM_DETAIL();
--
OPEN C_get_info;
FETCH C_get_info BULK COLLECT INTO O_item_data;
CLOSE C_get_info;
--
RETURN TRUE;
--
EXCEPTION
--
WHEN OTHERS THEN
--
IF C_get_info%ISOPEN THEN
--
CLOSE C_get_info;
--
END IF;
--
O_error_message := SQL_LIB.CREATE_MSG('PACKAGE_ERROR',
SQLERRM,
L_program,
TO_CHAR(SQLCODE));
RETURN FALSE;
--
--
END GET_STORE_ITEMS;
在最坏的情况下,返回的行数约为140万。有什么办法可以提高如此大量记录的查询性能?还是在将数据提取到输出结构时应该尝试其他方法?预先感谢。
答案 0 :(得分:1)
我实际上通过添加分页来解决了这个问题。正如Jon Heller在评论中所说,这不是与PL / SQL代码相关的性能问题。由于该函数返回的记录数量很多,因此需要控制在调用时应该返回多少数据。基于此,我改进了游标以限制返回的数据子集,并优化了查询以降低其成本。我还介绍了分页并定义了1000个记录的限制。
FUNCTION GET_STORE_ITEMS(I_store IN STORE.STORE%TYPE,
I_item_status IN WIN_STORE.STATUS%TYPE,
--------- pagination ----------
I_offset IN PLS_INTEGER DEFAULT NULL,
I_limit IN PLS_INTEGER DEFAULT NULL,
O_total_reg OUT PLS_INTEGER,
----------- output ------------
O_item_data OUT SYS_REFCURSOR,
----------- error -------------
O_error_message OUT VARCHAR2)
RETURN BOOLEAN IS
--
L_error_message VARCHAR2(500) := '';
L_skip PLS_INTEGER := I_offset;
L_take PLS_INTEGER := I_limit;
L_limit_take PLS_INTEGER := 1000;
L_tab_item_detail NB_TAB_ITEM_DETAIL := NB_TAB_ITEM_DETAIL();
--
CURSOR C_get_total_rec IS
--
SELECT COUNT(1)
FROM (
-- based on the main query --
-- ...
);
-- Get store items information.
CURSOR C_get_info IS
--
SELECT NB_REC_ITEM_DETAIL(sku => sku,
item_desc => desc_up,
system_ind => system_ind,
status => status,
div_no => division,
div_desc => div_name,
group_no => group_no,
group_desc => group_name,
dept_no => dept,
dept_desc => dept_name,
class_no => class,
class_desc => class_name,
subclass_no => subclass,
subclass_desc => sub_name,
var_weight_ind => nb_var_weight,
primary_ean => (SELECT upc as primary_ean
FROM upc_ean u
WHERE u.sku = tab.sku
AND u.primary_upc_ind = 'Y'
AND rownum = 1)
)
FROM ( -- main query --
-- ...
) tab
WHERE ROWNUM <= L_skip + L_take;
--
BEGIN
-- get the total number of records.
OPEN C_get_total_rec;
FETCH C_get_total_rec INTO O_total_reg;
CLOSE C_get_total_rec;
-- Set the pagination parameters to get all records by default.
IF L_skip IS NULL OR L_skip < 0 THEN
--
L_skip := 0; -- setting offset to 0
--
END IF;
--
IF L_take > L_max_take OR L_take < 0 OR L_take IS NULL THEN
--
L_take := L_max_take;
--
END IF;
--
OPEN C_get_info;
FETCH C_get_info BULK COLLECT INTO L_tab_item_detail LIMIT 1000;
CLOSE C_get_info;
--
-- Open item data sys_refcursor.
--
OPEN O_item_data for
--
SELECT *
FROM TABLE(L_tab_item_detail);
--
RETURN TRUE;
--
EXCEPTION
--
WHEN OTHERS THEN
--
-- ...
--
RETURN FALSE;
--
--
END GET_STORE_ITEMS;
谢谢大家!