Создание больших xml-файлов из oracle: рекомендации
в настоящее время я начинаю работу над проектом, где мне нужно будет написать код (pl/sql) для экспорта больших XML-файлов на основе нескольких таблиц в базе данных.
файлы экспорта могут стать довольно большими и могут содержать до 700.000 клиентов (с их адресами, заказами, номерами телефонов и т. д..).
Мне было интересно, есть ли у кого-нибудь советы по лучшему подходу к этому. Я мог бы, очевидно, просто написать selects с потерянными XMLELEMENTS в них, но это это означает, что весь файл будет сгенерирован в памяти.
также доступна XML-схема (XSD), которой должны соответствовать файлы. Мне также было интересно, есть ли способ "сопоставить" таблицу со схемой XML.
любые советы приветствуются.
3 ответов
XML имеет некоторые... недостатки в этой области. Большие XML-файлы, как вы заметили, могут hog RAM и отменить, как будто завтра нет.
Я честно не верю, что существует что-то под названием "Лучшие практики", все зависит от вашей собственной базы данных, сервера и запросов. Однако вот что сделал коллега (я не могу претендовать на кредит), чтобы написать огромные суммы (4,5 ГБ) XML на диск из большого числа (20?) больших таблиц (10-400М строк) с весьма сложным вложенный запрос.
фактически выпишите все эти XMLElements
Если ваша инструкция SELECT вообще сложна, сначала создайте таблицу.
-
выберите из таблицы, принимая разумный элемент, надеюсь, на основе вашего идентификатора. Например, если у вас есть следующая структура, имеет смысл разделить ее на
<record>
<someXML> <record ID="1"> <blah> <moreBlah/> </blah> </record> <record ID="2"> <blah> <moreBlah/> </blah> </record> </someXML>
выберите каждую запись как CLOB из база данных. Затем вы получите серию Клобов, которые будут составлять ваш выходной XML.
Сначала напишите открывающий тег, затем индивидуально или кусками, напишите каждый клоб на диск
убедитесь, что вы пишете на диск локально. Если этого нельзя избежать, напишите в сетевой ресурс, где есть большой толстый кабель, указывающий на него. Вы всегда можете переместить свой файл после этого, и это будет более эффективно, чем запись по сети (или городу/стране) в куски.
распараллелить! Это не всегда возможно, но если вы можете это сделать, сделайте это.
будьте осторожны с распараллеливанием. Вы не хотите писать искаженный XML.
Я эффективно пропагандирую подход tbone, вместо этого не делайте этого кусками. Что бы вы ни делали, старайтесь не заносить все это в память.
сначала попробуйте использовать DBMS_XMLGEN. Есть и другие подходы, смотрите это Oracle XML DB doc
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;
обратите внимание, что я позаимствовал большую часть этого из excellent oracle-base сайт
другой трюк-запись результатов в несколько XML-файлов, то есть, скажем, 10.000 строк на файл, такой как Table_01_Rows_00001_99999.XML. Затем при необходимости объедините XML-файлы позже.