请查看下表。整个数据在DOCSTART和DOCEND内。数据进一步包含在BACCSTART和BACCEND中。这种类型的块是可重复的。我必须为BACCSTART和BACCEND中的每个块拾取任何ABCD,它也是可重复的和TOTAL(每个块发生一次)和ACCNAME(每个块发生一次)并形成像
这样的xml<BACCSTART>
<TOTAL>100</TOTAL>
<ABCD>abcd</ABCD>
<ACCNAME>name</ACCNAME>
</BACCSTART>
每个这样的块。目前我正在使用for循环,但性能达不到标准。它将有大约200个这样的块,我必须在15秒内形成xmls。目前for循环大约需要53秒。
ROWNUM NAME VALUE
1 DOCSTART null
2 BACCSTART null
3 ABCD abcd
4 ABCD abcd2
5 PQRS pqrs
6 PQRS pqrs2
7 TOTAL 100
8 ACCNAME name
9 BACCEND null
10 BACCSTART null
11 ABCD abcd
12 ABCD abcd2
13 PQRS pqrs3
14 PQRS pqrs4
15 TOTAL 150
16 ACCNAME name
17 BACCEND null
18 DOCEND null
请帮我解决这个问题。如果通过时间有效的查询可以做到这一点。
是oracle 10g。
我刚刚对要求进行了修改。 ACCNAME的值存在于另一个约90行的cofig表中。从那里我必须拿起三个值,例如ACCNAME的value1和相应的value2和value3,并在xml中填充为标签。如果我加入该表,性能会受到影响。请建议。配置表就像
HEADER1 HEADER2 HEADER3 HEADER4 ........
<ACCNAME> value2 value3
.............
.............
.............
.............
我上面提到的数据,我从包含它的表中得到它。将它转换为clob并使用xmltable后,我得到了上述数据。在继续之前使用全局临时表来插入数据会更好吗?像
insert into data(row_num,name,value)
select /*+ no_xml_query_rewrite , parallel(x,8) */ rownum rn, substr(extractvalue(x.column_value,'/e'),1,instr(extractvalue(x.column_value,'/e'),' ')-1) name,
substr(extractvalue(x.column_value,'/e'),instr(extractvalue(x.column_value,'/e'),' ')+1) value
from dual,
xmltable('e' passing xmltype('<e><e>' ||
replace(long2clob('select longdata from billedacc order by segment_number'),
'|'||chr(10), '</e><e>') || '</e></e>').extract('e/e')
) x;
还建议是否有更好的方法来解决这个问题。
答案 0 :(得分:0)
鉴于9000个数据行(500 *您在上面提供的18个样本行),以下代码大约运行一秒钟,这应该达到您的性能目标:
DECLARE
l_xml_data XMLTYPE;
BEGIN
<<baccstart_loop>>
FOR r_baccstart IN (
-- Initially, get all start/end rows
WITH delimiters_all_rows AS (
SELECT d.*
FROM data d
WHERE d.name IN ('BACCSTART', 'BACCEND')
)
-- Lead over the rows order by row_num to get the start/end pairs
-- into a single row
, delimiters_all_rows_joined AS (
SELECT
dar.row_num baccstart_row_num
, LEAD(dar.row_num) OVER (ORDER BY row_num) baccend_row_num
, dar.name
FROM delimiters_all_rows dar
)
-- Eliminate the BACCEND rows as we have their row_num values
SELECT *
FROM delimiters_all_rows_joined darj
WHERE name = 'BACCSTART'
)
LOOP
-- Now get all relevant rows for this data block
WITH data_rows AS (
SELECT d.*
FROM data d
WHERE d.row_num > r_baccstart.baccstart_row_num AND d.row_num < r_baccstart.baccend_row_num
AND (
d.name IN ('TOTAL','ACCNAME')
OR (d.name = 'ABCD' AND d.row_num = (
SELECT MIN(d2.row_num)
FROM data d2
WHERE d2.row_num > r_baccstart.baccstart_row_num AND d2.row_num < r_baccstart.baccend_row_num
AND d2.name = 'ABCD'
))
)
)
-- Agg the rows into a single XML block (note: EVALNAME for dynamic XML element name)
SELECT
XMLELEMENT("BACCSTART"
, XMLAGG(
XMLELEMENT(EVALNAME(dr.name), dr.value)
ORDER BY DECODE(dr.name, 'TOTAL', 1, 'ABCD', 2, 3)
)
) xml_data
INTO l_xml_data
FROM data_rows dr;
INSERT INTO data_xml VALUES (l_xml_data);
END LOOP baccstart_loop;
END;
我试图让它在一个查询中完成所有工作,但是XMLAGG
性能似乎只要你应用GROUP BY
这么多行(我已经是看到一次又一次地发生)。当XMLAGG
被限制为尽可能少的行时,性能变得更加可接受。
生成的XML被插入到一个名为data_xml
的表中(这样我就可以很容易地看到结果),但是一旦生成了XML片段,您就可以替换所需的任何内容!
我建议您是否将数据插入表中,然后只需执行INSERT
/ SELECT
而不是SELECT INTO
,然后执行INSERT
由于缺少SQL和PL / SQL之间的上下文切换,所以会更快。
以下DDL / DML用于设置此示例:
CREATE TABLE data (
row_num INTEGER
, name VARCHAR2(10)
, value VARCHAR2(10)
)
/
CREATE TABLE data_xml (
xml_data XMLTYPE
)
/
CREATE SEQUENCE data_seq
START WITH 1
INCREMENT BY 1
CACHE 1000
/
BEGIN
FOR idx IN 1 .. 500 LOOP
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'DOCSTART', NULL);
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'BACCSTART', NULL);
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ABCD', 'abcd');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ABCD', 'abcd2');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'PQRS', 'pqrs');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'PQRS', 'pqrs2');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'TOTAL', '100');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ACCNAME', 'name');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'BACCEND', NULL);
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'BACCSTART', NULL);
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ABCD', 'abcd');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ABCD', 'abcd2');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'PQRS', 'pqrs3');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'PQRS', 'pqrs4');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'TOTAL', '150');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'ACCNAME', 'name');
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'BACCEND', NULL);
INSERT INTO data (row_num, name, value)
VALUES (data_seq.NEXTVAL, 'DOCEND', NULL);
END LOOP;
END;
/