Загрузка XML идет медленно. Использование text() при чтении XML-файла с сопоставлением, ориентированным на атрибуты

Я читаю файл XML в базу данных. Работает нормально, но очень медленно. Мне было интересно, могу ли я использовать text(), чтобы ускорить процесс, аналогично решению в этом посте: Запрос выбора Xml xpath работает медленно.
Однако моя проблема заключается в том, что решение предназначено для XML с сопоставлением, ориентированным на элементы, в то время как у меня сопоставление, ориентированное на атрибуты, поэтому я не уверен, как использовать text() в моем случае.

XML выглядит так

<Level1>
    <Level2 name = "l2_name">
        <Level3 name = "l3_name">
            <Level4 name = "l4_name">
                <Level5 name = "l5_name">
                    <Level6_1 name = "l6_1_name" value = "l6_1_value"/>
                    <Level6_2 name = "l6_2_name" value = "l6_2_value"/>

Я использую следующий код

declare @x xml

select @x = c1 
from openrowset(bulk 'd:\file.xml', single_blob) as table1(c1);

select
    c.value('@name', 'varchar(20)') as [col1],
    c2.value('@name', 'varchar(20)') as [col2],
    c3.value('@name', 'varchar(20)') as [col3],
    c4.value('@name', 'varchar(20)') as [col4],
    c5_1.value('@name', 'varchar(20)') as [col5],
    c5_1.value('@value', 'varchar(20)') as [col6],
    c5_2.value('@name', 'varchar(20)') as [col7],
    c5_2.value('@value', 'varchar(20)') as [col8],
from @x.nodes('Level1/Level2') as t(c)
cross apply c.nodes('Level3') as t2(c2)
cross apply c2.nodes('Level4') as t3(c3)
cross apply c3.nodes('Level5') as t4(c4)
cross apply c4.nodes('Level6_1') as t5_1(c5_1)
cross apply c4.nodes('Level6_2') as t5_2(c5_2)

Файл, который я читаю, имеет размер 13 МБ, и его чтение занимает 3,5 часа.

Иногда старый стиль sp_xml_preparedocument работает быстрее.

Alex Kudryashev 30.05.2019 05:16

Размещенный вами код не загружает файл XML в базу данных, он анализирует файла и извлекает атрибуты без импорта файла. Вопрос, на который вы ссылаетесь, - это совершенно другой случай - он загружает данные XML из поля XML, где данные уже были проанализированы, измельчены и сохранены в виде элементов XML. Связанный запрос показывает разницу между .value и text() при работе с элементами. Ваш запрос читается как атрибуты

Panagiotis Kanavos 30.05.2019 10:00

Попробуйте создать промежуточную таблицу с полем типа xml, которое покрыто индексом. Загрузите нужный XML-текст в это поле и запросите индексированное поле.

Panagiotis Kanavos 30.05.2019 10:01
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
3
1 058
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Не имея возможности протестировать столько строк, сколько у вас есть, я дам вам этот сценарий для опробования (рабочий пример<>):

DECLARE @x XML=N'
<Level1><Level2 name = "l2_name"><Level3 name = "l3_name">
<Level4 name = "l4_name"><Level5 name = "l5_name">
<Level6 name = "l6_name" value = "l6_value"/>
<Level6 name = "l6_name" value = "l6_value"/>
</Level5></Level4></Level3></Level2></Level1>';

SELECT
    x.n.value('../../../../@name', 'varchar(20)') as [col1],
    x.n.value('../../../@name', 'varchar(20)') as [col2],
    x.n.value('../../@name', 'varchar(20)') as [col3],
    x.n.value('../@name', 'varchar(20)') as [col4],
    x.n.value('./@name', 'varchar(20)') as [col5]
FROM
    @x.nodes('/Level1/Level2/Level3/Level4/Level5/Level6') AS x(n);

Это будет явно запрашивать узлы Level6, а затем возвращаться к значениям атрибутов родителей. Скорее всего, это быстрее, чем перекрестное применение запросов для каждого отдельного элемента LevelN.


Обновлено для элементов уровня 6 с разными именами и при условии, что только один такой элемент с каждым именем отображается как дочерний элемент уровня 5:

DECLARE @x_2 XML=N'<Level1>
    <Level2 name = "l2_name">
        <Level3 name = "l3_name">
            <Level4 name = "l4_name">
                <Level5 name = "l5_name">
                    <Level6_1 name = "l6_1_name" value = "l6_1_value"/>
                    <Level6_2 name = "l6_2_name" value = "l6_2_value"/>
                    </Level5></Level4></Level3></Level2></Level1>';

SELECT
    x.n.value('../../../@name', 'varchar(20)') as [col1],
    x.n.value('../../@name', 'varchar(20)') as [col2],
    x.n.value('../@name', 'varchar(20)') as [col3],
    x.n.value('./@name', 'varchar(20)') as [col4],
    x.n.value('(./Level6_1/@name)[1]', 'varchar(20)') as [col5],
    x.n.value('(./Level6_2/@name)[1]', 'varchar(20)') as [col6]
FROM
    @x_2.nodes('/Level1/Level2/Level3/Level4/Level5') AS x(n);

Это выбирает узлы на уровне 5, возвращается к родителям для родительских атрибутов, затем выбирает дочерние элементы на основе имени. Выбирает первый такой элемент с помощью селектора [1].

Верно. Перейдите на самый глубокий уровень в Xpath (6), затем используйте относительные пути обратно к родителям, чтобы избежать перекрестных соединений. Это также была бы моя первая попытка закодировать это.

granadaCoder 30.05.2019 15:35

@ТТ. Спасибо за ответ. Однако как бы я использовал ваш запрос, если бы у меня было две разные записи на уровне 6? Должен ли я все еще apply это со второго @xnodes? Я отредактировал свои вопросы, чтобы отобразить его.

Alex.S 30.05.2019 23:06

@ Alex.S Я обновил ответ, но, пожалуйста, не меняйте свой вопрос каждый раз.

TT. 31.05.2019 12:50

@ Alex.S Это быстрее и достаточно быстро?

TT. 01.06.2019 09:18

@ТТ. Жаль был в отъезде. Это быстрее, но не намного. Я думаю, это то же самое, что и с XML. Спасибо

Alex.S 05.06.2019 22:16

@Alex.S Если у вас есть XML в таблице, возможно, с XML-индексированием он станет еще быстрее (хотя также необходимо учитывать время загрузки).

TT. 06.06.2019 06:14

@ Alex.S Недавно я прочитал, что использование OPENXML может быть намного более эффективным. Возможно, вам стоит попробовать. Некоторые примеры здесь.

TT. 18.08.2019 10:16

Другие вопросы по теме