我目前正在开展一个项目,我将不得不编写代码 (pl/sql) 以基于数据库中的多个表导出大型 XML 文件。
导出文件可能会变得非常大,并可能包含多达 700.000 个客户(包括他们的地址、订单、电话号码等)。
我想知道是否有人对此的最佳方法有一些提示。我显然可以只写出其中丢失了 XMLELEMENTS 的选择,但这意味着整个文件将在内存中生成。
还有一个可用的 XML 模式 (XSD),文件必须遵守该模式。我还想知道是否有任何方法可以将表“映射”到 XML 模式。
任何提示表示赞赏。
XML 在这方面有一些……缺点。正如您所注意到的,大型 XML 文件可能会占用 RAM 和 UNDO,就像没有明天一样。
老实说,我不相信存在所谓的“最佳实践”,这完全取决于您自己的数据库、服务器和查询。然而,这是一个同事(我不能声称功劳)为了从大量(20?)个极其复杂的大型表(10-400m 行)中将大量(4.5GB)的 XML 写入磁盘而完成的。子查询。
实际上写出所有这些 XMLElements
如果您的 SELECT 语句非常复杂,请先创建一个表。
从表格中选择一个合理的元素,希望基于您的 ID。例如,如果您具有以下结构,则将其拆分是有意义的<record>
<someXML>
<record ID="1">
<blah>
<moreBlah/>
</blah>
</record>
<record ID="2">
<blah>
<moreBlah/>
</blah>
</record>
</someXML>
从数据库中选择每条记录作为 CLOB。然后,您将得到一系列组成输出 XML 的 CLOB。
首先写入开始标签,然后单独或以块的形式将每个 CLOB 写入磁盘
确保您在本地写入磁盘。如果无法避免写入网络共享,那里有一根粗大的电缆指向它。之后您始终可以移动文件,这比通过网络(或城市/国家)分块写入更有效。
并行化!这并不总是可能的,但如果你能做到,那就这样做。
小心并行化。您不想编写格式错误的 XML。
I'm effectively advocating tbone's approach, save doing it in chunks instead. Whatever you do avoid putting the entire thing in memory.
首先尝试使用 DBMS_XMLGEN。还有其他方法,请参阅此Oracle XML DB文档
DECLARE
v_ctx DBMS_XMLGEN.ctxhandle;
v_file UTL_FILE.file_type;
v_xml CLOB;
v_more BOOLEAN := TRUE;
BEGIN
-- Create XML context.
v_ctx := DBMS_XMLGEN.newcontext('SELECT table_name, tablespace_name FROM user_tables WHERE rownum < 6');
-- Set parameters to alter default Rowset and Row tag names and default case.
DBMS_XMLGEN.setrowsettag(v_ctx, 'USER_TABLES');
DBMS_XMLGEN.setrowtag(v_ctx, 'TABLE');
--DBMS_XMLGEN.settagcase(v_ctx, DBMS_XMLGen.LOWER_CASE);
-- Add an IE specfic XSL stylesheet reference so browser can transform the file.
--DBMS_XMLGEN.setstylesheetheader(v_ctx, 'C:\Development\XML\IEStyle.xsl', 'text/xsl');
-- Create the XML document.
v_xml := DBMS_XMLGEN.getxml(v_ctx);
DBMS_XMLGEN.closecontext(v_ctx);
-- Output XML document to file.
v_file := UTL_FILE.fopen('C:\Development\XML\', 'test1.xml', 'w');
WHILE v_more LOOP
UTL_FILE.put(v_file, SUBSTR(v_xml, 1, 32767));
IF LENGTH(v_xml) > 32767 THEN
v_xml := SUBSTR(v_xml, 32768);
ELSE
v_more := FALSE;
END IF;
END LOOP;
UTL_FILE.fclose(v_file);
-- test insert into table
/*
insert into t_clob (clob_col) values (v_xml);
commit;
*/
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.put_line(Substr(SQLERRM,1,255));
UTL_FILE.fclose(v_file);
END;
请注意,我从优秀的oracle-base站点借用了大部分内容
Another trick is writing the results into multiple XML files, ie say 10.000 rows per file like Table_01_Rows_00001_99999.xml. Then merge XML files later if necessary.