Я читаю файл 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 часа.
Размещенный вами код не загружает файл XML в базу данных, он анализирует файла и извлекает атрибуты без импорта файла. Вопрос, на который вы ссылаетесь, - это совершенно другой случай - он загружает данные XML из поля XML, где данные уже были проанализированы, измельчены и сохранены в виде элементов XML. Связанный запрос показывает разницу между .value
и text()
при работе с элементами. Ваш запрос читается как атрибуты
Попробуйте создать промежуточную таблицу с полем типа xml, которое покрыто индексом. Загрузите нужный XML-текст в это поле и запросите индексированное поле.
Не имея возможности протестировать столько строк, сколько у вас есть, я дам вам этот сценарий для опробования (рабочий пример<>):
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), затем используйте относительные пути обратно к родителям, чтобы избежать перекрестных соединений. Это также была бы моя первая попытка закодировать это.
@ТТ. Спасибо за ответ. Однако как бы я использовал ваш запрос, если бы у меня было две разные записи на уровне 6? Должен ли я все еще apply
это со второго @xnodes
? Я отредактировал свои вопросы, чтобы отобразить его.
@ Alex.S Я обновил ответ, но, пожалуйста, не меняйте свой вопрос каждый раз.
@ Alex.S Это быстрее и достаточно быстро?
@ТТ. Жаль был в отъезде. Это быстрее, но не намного. Я думаю, это то же самое, что и с XML. Спасибо
@Alex.S Если у вас есть XML в таблице, возможно, с XML-индексированием он станет еще быстрее (хотя также необходимо учитывать время загрузки).
@ Alex.S Недавно я прочитал, что использование OPENXML
может быть намного более эффективным. Возможно, вам стоит попробовать. Некоторые примеры здесь.
Иногда старый стиль
sp_xml_preparedocument
работает быстрее.