Tit*_*mir 5 xml sql-server xpath xquery sql-server-2012
我有一个xml变量,其中包含一组要在表中查找的ID。查询时,我尝试了多个版本,但以下(根据我的测试)似乎是最快的:
declare @idsxml as xml (IdSchemaColelction) = '<root><Id>505766</Id><Id>458073</Id><Id>460689</Id><Id>464050</Id></root>'
SELECT * FROM entity
WHERE @idsXml.exist('/root/Id[data(.)=sql:column("id")]') = 1
Run Code Online (Sandbox Code Playgroud)
问题在于查询计划具有以下警告“表达式中的类型转换(CONVERT_IMPLICIT(sql_variant,CONVERT_IMPLICIT(numeric(38,10),[xmlTest]。[dbo]。[dbo]。[entity]。[id],0),0 ))可能会影响查询计划选择中的“ CardinalityEstimate”
我创建了一个XML模式,该模式将Id的文本定义为整数,因此我希望这data(.)=sql:column("id")是整数之间的比较,但此警告可能会导致其他情况。
在这种情况下,删除此警告的正确方法是什么?这是否会对性能产生影响?
表定义和架构定义:
CREATE XML SCHEMA COLLECTION IdSchemaColelction AS '
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" >
<xs:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes"
schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd"/>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Id" type="sqltypes:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
'
go
create table entity ( id int not null primary key)
Run Code Online (Sandbox Code Playgroud)
我不认为你的方法是最好或最快的......
以下是一些比较它们的方法:
用它进行测试
create table test ( id int not null primary key);
insert into test VALUES(100),(200),(505766),(300),(400),(500),(458073),(600),(700),(464050),(800),(900),(1000)
GO
Run Code Online (Sandbox Code Playgroud)
这是你的 id 列表
declare @idsxml as xml = '<root><Id>505766</Id><Id>458073</Id><Id>460689</Id><Id>464050</Id></root>'
Run Code Online (Sandbox Code Playgroud)
——这就是你的做法。它将一遍又一遍地解析 XML — .data()— 当然 — — 不是读取类型安全数据进行比较的最佳方式...
SELECT test.id
FROM test
WHERE @idsXml.exist('/root/Id[data(.)=sql:column("id")]') = 1;
Run Code Online (Sandbox Code Playgroud)
--这是完全相同的方法,但 XQuery 更快
SELECT test.id
FROM test
WHERE @idsXml.exist('/root/Id[text()=sql:column("id")]') = 1;
Run Code Online (Sandbox Code Playgroud)
--这有点慢...可能是因为有隐式类型转换...
SELECT test.id
FROM test
WHERE @idsXml.exist('/root[Id=sql:column("id")]') = 1;
Run Code Online (Sandbox Code Playgroud)
-- 对于较大的列表,最好使用派生表INNER JOIN
WITH DerivedTable AS
(
SELECT i.value('.','int') AS id
FROM @idsxml.nodes('root/Id') AS A(i)
)
SELECT test.id
FROM test
INNER JOIN DerivedTable AS dt ON test.id=dt.id;
Run Code Online (Sandbox Code Playgroud)
--对于一个大列表,您甚至可能会考虑一个索引声明表(阅读in memory最后的量子速度)
DECLARE @tbl TABLE(id INT NOT NULL PRIMARY KEY) --PK only, if your XML never contains a value twice!
INSERT INTO @tbl
SELECT i.value('.','int') AS id
FROM @idsxml.nodes('root/Id') AS A(i);
SELECT test.id
FROM test
INNER JOIN @tbl AS tbl ON test.id=tbl.id;
GO
DROP TABLE test;
Run Code Online (Sandbox Code Playgroud)