8

我目前正在开展一个项目,我将不得不编写代码 (pl/sql) 以基于数据库中的多个表导出大型 XML 文件。

导出文件可能会变得非常大,并可能包含多达 700.000 个客户(包括他们的地址、订单、电话号码等)。

我想知道是否有人对此的最佳方法有一些提示。我显然可以只写出其中丢失了 XMLELEMENTS 的选择,但这意味着整个文件将在内存中生成。

还有一个可用的 XML 模式 (XSD),文件必须遵守该模式。我还想知道是否有任何方法可以将表“映射”到 XML 模式。

任何提示表示赞赏。

4

3 回答 3

6

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.

于 2013-06-03T20:47:14.120 回答
3

首先尝试使用 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站点借用了大部分内容

于 2013-06-03T20:37:26.207 回答
0

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.

于 2016-02-09T18:40:45.867 回答