У меня есть набор процедур SQL в SQL Server 2008 R2, которые в конечном итоге создают большой XML-файл, который собирается SSIS и сохраняется в папке ftp для клиента. Все работает отлично для относительно небольших наборов данных, но производительность для процессоров слишком неподходящая; Мне нужно сделать все быстрее, если смогу.Более эффективное создание файла XML, чем SQL Server ДЛЯ EXPLICIT
Вот краткое изложение текущих шагов, которые принимаются каждый раз, когда XML производится (все этапы называются пакетом SSIS, который в конечном счете принимает XML обратно и сохраняет его):
- Данные, полученные от Живая база данных в моей базе данных
- Данные преобразуются в другую таблицу (так называемый Proto_XML), поэтому она имеет структуру, необходимую для работы
FOR XML EXPLICIT
(с именами столбцов, такими как[ParentName!2!TagName!ELEMENT]
, множеством повторяющихся данных, множеством нулей и тегами и родительскими идентификаторами в каждая строка, но индексы по всем столбцам, которые впоследствии используются для заказа результатов). SELECT * FROM Proto_XML ORDER BY... FOR XML EXPLICIT
запрос, выполненный в таблице Proto_XML, для создания XML-файла.- Около 12 строк xquery запускаются на xml для очистки. Они в основном похожи на такие вещи:
SET @XML.modify('delete //Data31/*//*[empty(.//text())]')
. Хотелось бы, чтобы я мог избежать этого шага, тем более, что он предполагает использование нетипизированного XML, но не нашел способа создать XML без пустых элементов, по крайней мере, в некоторых местах. - Попытка проверить xml на схему; если это удастся, верните xml. Я избегал фактически применять схему к xml, так как это преобразует форматированные числа в их канонические значения.
Я просмотрел много информации о том, как можно ускорить последние три шага, которые все в одной процедуре (для большого файла потребовалось более 6 часов!). Однако я не смог увидеть, как я могу применить любое из этих предложений в этом случае; учитывая размер и сложность XML, я действительно не думаю, что смогу использовать FOR XML AUTO
или FOR XML RAW
, как предлагают некоторые сайты. Существуют также различные предложения по улучшению скорости преобразований FOR XML EXPLICIT
, но я не вижу, как я могу сделать что-то проще для FOR XML EXPLICIT
, чем ссылаться на правильно отформатированную, индексированную таблицу, как я сейчас делаю.
Возможное решение было предложено в this question, но я не нашел совета относительно того, как преобразовать полный результат. Установить в XML-файл в SSIS (предположительно, используя задачу скрипта), если это то, что означает ответ. Было также принято решение на раннем этапе проекта, чтобы избежать использования задачи сценария для задания в (неверном?) Убеждении, что это будет еще медленнее, чем SQL.
Таким образом, мой вопрос: что бы вы порекомендовали попробовать, чтобы узнать о ускорении создания файла xml? Должен ли я использовать что-то отличное от SQL Server для этого шага, и если да, то у вас есть идеи о том, что я должен использовать/любые ключевые слова или ссылки, которые я могу использовать, чтобы узнать, как добиться создания xml?
это мясо, что FOR XML EXPLICIT
процедура, которая занимает так много времени, как выглядит (все имена были удалены):
IF OBJECT_ID('tempdb..#Results') IS NOT NULL DROP TABLE #Results
DECLARE @SchemaError NVARCHAR(1000)
CREATE TABLE #Results
(Value XML NOT NULL)
DECLARE
@AvailableFields VARCHAR(MAX) = ''
,@OrderBy VARCHAR(MAX)
,@SQL VARCHAR(MAX) = ''
,@Untyped_XML XML
,@XML XML(DataFeed_Schema)
---------------------------------------------------------------------------------------------------------------
-- We should attempt to select all fields from the available data table, unless restricted in the formatting of
-- the datafeed itself.
SELECT
@AvailableFields = @AvailableFields + QUOTENAME(Col.name) + ','
FROM
MyDataBase.sys.columns AS Col
WHERE
Col.object_id = OBJECT_ID('MyDataBase.dbo.Proto_XML')
-- ignore the identity column; we only want the ones that actually go in the XML, starting with "Tag"
AND Col.name <> 'Id'
ORDER BY
Col.column_id
SELECT @AvailableFields = LEFT(@AvailableFields,LEN(@AvailableFields)-1)
SELECT @OrderBy = '
[Level4!4!Name!ELEMENT]
,[Data6!6!Label!ELEMENT]
,[Data10!10!Name!ELEMENT]
,[Data12!12!Label!ELEMENT]
,[Data16!16!Name!ELEMENT]
,[Data18!18!Label!ELEMENT]
,[Data22!22!Number!ELEMENT]
,[Data23!23!Name!ELEMENT]
,[Data25!25!Name!ELEMENT]
,[Data29!29!Name!ELEMENT]
,[Data31!31!CreateDate!ELEMENT]
,[Data32!32!LastName!ELEMENT]
,[Data34!34!Label!ELEMENT]
,[Data37!37!Label!ELEMENT]
,[Data39!39]
,[Data40!40!Name!ELEMENT]
,[Data42!42!CreateDate!ELEMENT]
,[Data46!46!Id!ELEMENT]
,[Data48!48!Id!ELEMENT]
,[Data50!50!Id!ELEMENT]
,[Data53!53!Id!ELEMENT]
,[Data54!54]
,[Data55!55!Type!ELEMENT]
,Tag
,Parent'
---------------------------------------------------------------------------------------------------------------
-- Use our list of columns to select what we want into our temporary table (the table is just used so that a
-- variable can be referenced in the dynamic sql and in the main query).
SELECT @SQL =
'INSERT #Results(Value)
SELECT
(SELECT ' + @AvailableFields + '
FROM Proto_XML
ORDER BY' + @OrderBy + '
FOR XML EXPLICIT
)'
PRINT (@SQL)
EXEC (@SQL)
-- Pop our newly created XML into a variable ready for its spring clean.
SELECT @Untyped_XML = Value FROM #Results
---------------------------------------------------------------------------------------------------------------
-- Delete all empty nodes below the __ Level
SET @Untyped_XML.modify('delete //Data31/*//*[empty(.//text())]')
-- Delete all empty nodes exactly one level below __ (This will leave the parent, but will not affect those
-- more levels below (e.g will not delete the empty parents left below __)
SET @Untyped_XML.modify('delete //Data22/*/*[empty(.//text())]')
-- do the same below __, __ and __
SET @Untyped_XML.modify('delete //Data54/*[empty(.//text())]')
SET @Untyped_XML.modify('delete //Data48/*[empty(.//text())]')
SET @Untyped_XML.modify('delete //Data46/*[empty(.//text())]')
-- We use "_" to indicate an empty label, so that the line above does not delete the parent __ level
-- from __. Now that we have done the step above, we can delete the __ that are so marked.
SET @Untyped_XML.modify('delete //Data29/Data33/Data34[. = "_"]')
SET @Untyped_XML.modify('delete //ClaimantInfo/CustomFields/CustomField[. = "_"]')
SET @Untyped_XML.modify('delete //Claim/CoverStatus/PurposeOfTrip[. = "_"]')
-- Delete all empty __, __ and __ empty custom fields.
SET @Untyped_XML.modify('delete //Data12/CustomFields/*[empty(.//text())]')
SET @Untyped_XML.modify('delete //Data10/CustomFields/*[empty(.//text())]')
SET @Untyped_XML.modify('delete //Data4/CustomFields/*[empty(.//text())]')
-- There are some mandatory fields - if these have empty indicators, they need to be emptied.
SET @Untyped_XML.modify('replace value of (//Data31/Data32[text() = "_"]/text())[1] with ""')
-- Add version and NameSpace information
SELECT @Untyped_XML = REPLACE(CONVERT(VARCHAR(MAX),@Untyped_XML),'<DataFeed>','<?xml version ="1.0"?>
<DataFeed xmlns ="http://tempuri.org/MyData.xsd">')
-- See if we can get the XML into the schema...
BEGIN TRY
SELECT @XML = @UNTYPED_XML
END TRY
BEGIN CATCH
SELECT @SchemaError = ERROR_MESSAGE()
END CATCH
IF @SchemaError IS NULL
SELECT @Untyped_XML AS DataFeedContent
ELSE
SELECT @SchemaError AS 'ErrorEncountered', @Untyped_XML AS FailedXML
---------------------------------------------------------------------------------------------------------------
DROP TABLE #Results
Посмотрите на ['FOR XML PATH'] (http://msdn.microsoft.com/en-us/library/ms189885.aspx) - намного проще и эффективнее, чем материал' FOR XML EXPLICIT'. –
Мне не удалось воссоздать сложность моего XML с помощью 'FOR XML PATH'. Для этого есть две возможные причины: «FOR XML PATH» ограничен, или мне нужно больше учиться. Я с удовольствием попробую узнать больше, но определенно ли он способен создавать сложные и настраиваемые биты XML? Я только вопрос, потому что я пробовал и не смог ... –