需求:統計所有渠道底下的商戶總數
數據庫情況:
一張user表,通過userTpye來區別是渠道還是商戶,並且渠道是有多層級的。
一張機構表,每個機構有個orgCode字段來展示渠道層級,比如:1,12,135:表示135機構的上級是12,12的上級是1
當時庫裏有28000多條數據,公司是最高層級,底下有100多個渠道。
如果對每個渠道做數狀查詢計算底下商戶總數:
s.org_id in (select c.id from sys_organization c start with c.id = #{code} connect by prior c.id = c.pid)
這種數狀查詢需要檢索整個user表,100多渠道就需要檢索100多次,每次瀏覽2萬多條數據,計算量非常大。
所以當時我換一個做法,我把user表裏的用戶org_id對應的機構表orgCode取出來,那麼一共有28000個orgCode,然後通過java的for循環來進行統計,比如1,12,135出現的時候,對應的1渠道商戶數+1,對應的12渠道和135渠道的商戶數也+1.這樣只要做一次for循環就能把所有商戶的歸屬渠道統計出來。
這個看似可以解決問題,但是卻遇見了一個新的問題,就是我要把商戶的code集合從oracle中取出來時,2萬多條的數據集合從數據庫取到java服務器耗費了大量的時間。我用PL/SQL時也是,查詢條件可以0.2秒出結果,但是要展示所有的列卻花了十幾秒。我猜測這可能是由於數據庫需要展示數據時要進行I/O操作,這個操作的讀寫浪費了大量的時間。
所以我考慮在數據庫存儲過程裏面完成這個統計操作。下面是存儲過程全文,這個存儲過程裏運用了比較多的語法,所以我特地記下來。
create or replace procedure getAgentMerCountMap(orgId varchar2,codeIdList out varchar2,codeNumList out varchar2)
as
TYPE c_mer_acount IS RECORD
( id number,
m_count number
);
---根據自定義數據類型創建一個集合
TYPE c_mer_acount_list IS TABLE OF c_mer_acount INDEX BY BINARY_INTEGER;
---集合對象
mer_acount_list c_mer_acount_list;
---數據對象
mer_acount c_mer_acount;
---計數器
v_counter number;
---計算code長度
code_len number;
code_count number;
m_code number;
cursor c_test is
select nuse.id,mer_name,nuse.createdatetime,sorg.code org_code from SYS_USER nuse,SYS_ORGANIZATION sorg where sorg.id=nuse.organization_id
and nuse.ISDEFAULT = '1' and nuse.ISDEL = '0'
and nuse.ORGANIZATION_ID in (select c.id from sys_organization c start with c.id = orgId connect by prior c.id = c.pid);
c_t c_test%rowtype;
begin
DBMS_OUTPUT.ENABLE (buffer_size=>null);
--不同code渠道的下屬商戶數量,key爲id,m_count爲人數。最後統計時要減一(減自身)
for c_t in c_test loop
--dbms_output.put_line( c_t.mer_name || '-0-' || c_t.org_code);
--獲取code長度
code_len:=LENGTH (c_t.org_code) - LENGTH (REPLACE (c_t.org_code, ',', ''))+1;
--循環取出code並賦值給 mer_acount_list集合
for code_count in 1..code_len loop
--註釋:REGEXP_SUBSTR('變量','正則分隔符','從第幾個算起','取第幾個')
m_code:=REGEXP_SUBSTR(c_t.org_code,'[^,]+',1,code_count);
--如果code存在則value+1,否則新建該code渠道
if mer_acount_list.exists(m_code) then
mer_acount := mer_acount_list(m_code);
mer_acount.m_count := mer_acount.m_count+1;
mer_acount_list(m_code) := mer_acount;
ELSE
mer_acount.id:=m_code;
--這裏實現了統計減一,將設置初始值爲0
mer_acount.m_count := 0;
mer_acount_list(m_code) := mer_acount;
end if;
end loop;
end loop;
codeIdList := '';
codeNumList := '';
v_counter := 0;
code_count := 1;
--將code集合用‘,’分隔封裝進返回參數codeIdList和codeNumList中。
while v_counter<mer_acount_list.count loop
if mer_acount_list.exists(code_count) then
mer_acount := mer_acount_list(code_count);
codeIdList := codeIdList || to_char(code_count) || ',';
codeNumList := codeNumList || mer_acount.m_count || ',';
v_counter := v_counter+1;
end if;
code_count := code_count+1;
end loop;
--dbms_output.put_line( codeIdList || '-0-' || codeNumList);
end;