내 질문은 이것을 기반으로합니다 : https : //.com/q/35575990/5089204
거기에 대한 답변을 제공하기 위해 다음 테스트 시나리오를 수행했습니다.
테스트 시나리오
먼저 테스트 테이블을 만들고 100.000 행으로 채 웁니다. 난수 (0 ~ 1000)는 각 난수에 대해 ~ 100 개의 행으로 이어져야합니다. 이 숫자는 varchar col에 입력되며 XML의 값으로 사용됩니다.
그런 다음 OP와 같은 호출을 수행하면 .exist () 및 .nodes ()가 필요하지만 두 번째에는 약간의 이점이 있지만 5-6 초가 걸립니다. 캐시 된 결과 나 계획을 통한 오 탐지 (false positive)를 피하기 위해 두 번의 순서로 전화를 걸었습니다. 두 번째는 교체 된 순서로, 검색 매개 변수가 약간 변경되고 전체 경로 대신 "// item"으로 변경되었습니다.
그런 다음 XML 인덱스를 만들고 동일한 호출을 수행합니다.
지금-정말 놀랐던 점! - .nodes
으로 전체 경로 훨씬 느린 (8 초)보다도 있지만은 .exist()
으로 0.5 초까지이고 전체 경로 에도 다운 0.10 초. (반면 .nodes()
에 짧은 경로가 더 나은,하지만 여전히 멀리 뒤에 .exist()
)
질문 :
내 자신의 테스트는 짧게 나타납니다. XML 인덱스는 데이터베이스를 크게 손상시킬 수 있습니다. 그것들은 일의 속도를 늦출 수 있지만 (s. 편집 2) 쿼리 속도를 늦출 수 있습니다. 어떻게 작동하는지 이해하고 싶습니다 ... XML 인덱스는 언제 만들어야합니까? .nodes()
색인이없는 것보다 색인이 더 나쁜 이유는 무엇 입니까? 어떻게 부정적인 영향을 피할 수 있습니까?
CREATE TABLE #testTbl(ID INT IDENTITY PRIMARY KEY, SomeData VARCHAR(100),XmlColumn XML);
GO
DECLARE @RndNumber VARCHAR(100)=(SELECT CAST(CAST(RAND()*1000 AS INT) AS VARCHAR(100)));
INSERT INTO #testTbl VALUES('Data_' + @RndNumber,
'<error application="application" host="host" type="exception" message="message" >
<serverVariables>
<item name="name1">
<value string="text" />
</item>
<item name="name2">
<value string="text2" />
</item>
<item name="name3">
<value string="text3" />
</item>
<item name="name4">
<value string="text4" />
</item>
<item name="name5">
<value string="My test ' + @RndNumber + '" />
</item>
<item name="name6">
<value string="text6" />
</item>
<item name="name7">
<value string="text7" />
</item>
</serverVariables>
</error>');
GO 100000
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesFullPath_no_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistFullPath_no_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('//item[@name="name5" and value/@string="My test 500"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistShortPath_no_index;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('//item[@name="name5" and value/@string="My test 500"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesShortPath_no_index;
GO
CREATE PRIMARY XML INDEX PXML_test_XmlColum1 ON #testTbl(XmlColumn);
CREATE XML INDEX IXML_test_XmlColumn2 ON #testTbl(XmlColumn) USING XML INDEX PXML_test_XmlColum1 FOR PATH;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesFullPath_with_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('/error/serverVariables/item[@name="name5" and value/@string="My test 600"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistFullPath_with_index;
GO
DECLARE @d DATETIME=GETDATE();
SELECT *
FROM #testTbl
WHERE XmlColumn.exist('//item[@name="name5" and value/@string="My test 500"]') = 1;
SELECT CAST(GETDATE()-@d AS TIME) AS ExistShortPath_with_index;
GO
DECLARE @d DATETIME=GETDATE()
SELECT #testTbl.*
FROM #testTbl
CROSS APPLY XmlColumn.nodes('//item[@name="name5" and value/@string="My test 500"]') AS a(b);
SELECT CAST(GETDATE()-@d AS TIME) AS NodesShortPath_with_index;
GO
DROP TABLE #testTbl;
편집 1-결과
이것은 SQL Server 2012가 중간 랩톱에 로컬로 설치된 결과 중 하나입니다 NodesFullPath_with_index
.
NodesFullPath_no_index 6.067
ExistFullPath_no_index 6.223
ExistShortPath_no_index 8.373
NodesShortPath_no_index 6.733
NodesFullPath_with_index 7.247
ExistFullPath_with_index 0.217
ExistShortPath_with_index 0.500
NodesShortPath_with_index 2.410
더 큰 XML로 테스트 2 편집
TT의 제안에 따르면 위의 XML을 사용했지만 item
약 450 항목에 도달 하도록 -nodes를 복사했습니다 . XML에서 히트 노드를 매우 높게 설정했습니다. ( .exist()
첫 번째 히트에서 멈추고 .nodes()
계속 진행할 것이라고 생각하기 때문에 )
XML 색인을 생성하면 mdf 파일이 ~ 21GB로 확장되었으며 ~ 18GB는 색인에 속하는 것으로 보입니다 (!!!)
NodesFullPath_no_index 3min44
ExistFullPath_no_index 3min39
ExistShortPath_no_index 3min49
NodesShortPath_no_index 4min00
NodesFullPath_with_index 8min20
ExistFullPath_with_index 8,5 seconds !!!
ExistShortPath_with_index 1min21
NodesShortPath_with_index 13min41 !!!
.nodes()
과.exist()
설득력 에 대한 당신의 생각 . 또한 색인full path search
이 더 빠르다 는 사실은 이해하기 쉬운 것 같습니다. 이것은 의미 : 당신은 XML 인덱스를 만들 경우, 당신은해야한다 항상 어떤 일반적인 XPath를 (에 부정적인 영향을 인식//
하거나*
또는..
또는[filter]
또는 아무것도 그냥 일반 XPath는 ...). 사실 당신은 전체 경로 만 사용해야합니다. – 꽤 훌륭한 추첨 ...