Что быстрее .exist или .value в предложении where?

#sql-server #performance #xpath #xquery-sql

#sql-сервер #Производительность #xpath #xquery-sql

Вопрос:

Я делаю несколько грубых тестов с типом данных xml SQL Server 2008. Я видел много мест, где .exist используется в where предложениях. Недавно я сравнил два запроса и получил странные результаты.

 select count(testxmlrid) from testxml
where Attributes.exist('(form/fields/field)[@id="1"]')=1
  

Выполнение этого запроса занимает около 1,5 секунд, без индексов для чего-либо, кроме первичного ключа (testxmlrid)

 select count(testxmlrid) from testxml
where Attributes.value('(/form/fields/field/@id)[1]','integer')=1
  

Этот запрос с другой стороны занимает около .до запуска осталось 75 секунд.

Я использую нетипизированный XML, и мой бенчмаркинг выполняется на экземпляре SQL Server 2008 Express. В наборе данных около 15 000 строк, и каждая строка XML имеет длину около 25 строк.

Верны ли эти результаты, которые я получаю? Если да, то почему все используют .exist ? Я делаю что-то неправильно и .exist могло бы быть быстрее?

Ответ №1:

Вы не учитываете одни и те же вещи. Ваш .exist запрос (form/fields/field)[@id="1"] проверяет все вхождения @id в XML, пока не найдет одно со значением 1 , а ваш .value запрос (/form/fields/field/@id)[1] извлекает только первое вхождение @id .

Протестируйте это:

 declare @T table
(
  testxmlrid int identity primary key,
  Attributes xml
)

insert into @T values
('<form>
    <fields>
      <field id="2"/>
      <field id="1"/>
    </fields>
  </form>')

select count(testxmlrid) from @T
where Attributes.exist('(form/fields/field)[@id="1"]')=1

select count(testxmlrid) from @T
where Attributes.value('(/form/fields/field/@id)[1]','integer')=1
  

Количество .exist запросов равно 1, потому что оно находит @id=1 во втором field узле, а количество .value запросов равно 0, потому что оно проверяет значение только для первого вхождения @id .

.exist Запрос, который проверяет значение только при первом появлении @id подобного вашему .value запроса, будет выглядеть следующим образом.

 select count(testxmlrid) from @T
where Attributes.exist('(/form/fields/field/@id)[1][.="1"]')=1
  

Комментарии:

1. exist() Не происходит короткого замыкания, как только оно находит первое вхождение в любом случае?

2. @Yuck — Да, это так, но в этом случае .exist запрос ищет наличие @id=1 . Если первое вхождение if @id отличается от 1, поиск продолжается. .value Запрос просматривает значение для первого вхождения @id и не продолжает поиск, если это значение не равно 1.

Ответ №2:

Разница может заключаться в ваших индексах.

PATH Индекс повысит производительность exist() предиката в WHERE предложении, тогда как PROPERTY индекс повысит производительность value() функции.

Прочитайте:http://msdn.microsoft.com/en-us/library/bb522562.aspx