2017-11-29 26 views
1

少し時間がかかるクエリを改善しようとしています(間違った場所を探しているかもしれませんが、XMLは開始するのに適していることがわかります。今のところ行くつもりです)。SQL Server XML Exist()を使用してパフォーマンスに参加する

XMLは次のようになります。

<BlockModels> 
    <BlockModel id="1"></BlockModel> 
</BlockModels> 

かなり簡単で残念ながら私のコントロール外です。これは固定フォーマット/定義です。

SQLステートメントは次のようになります。私は、このマニュアルに従ってきた

SELECT bm.Name, b.BlockModel.value('(./@id)[1]', 'INT') 
FROM @iBlockModels.nodes('/BlockModels/BlockModel') AS b(BlockMOdel) 
INNER JOIN BlockModel AS bm 
    ON (bm.Block_Model_Id = b.BlockModel.value('(./@id)[1]', 'INT')) 

https://docs.microsoft.com/en-us/sql/t-sql/xml/value-method-xml-data-type、これは静的な型指定([1])の構文を取得した場所です。しかし、パフォーマンスはあまり改善されていないようです。

上記のドキュメントでは、の代わりにexist()を使用してDを指摘していますが、この例では2つのテーブルを結合することはできません。私はそれが可能ではないと思うし、上記のものを例のようなものに変換しようとする私の試みは、それが壮観に失敗する原因となった。誰でも変換を支援できますか?パフォーマンスを助けるために他に何かできることを指摘しますか?

+0

は、それはあなたに与えますそれを行う方法の例。 'sql:column'部分では、単に列名を入れます。例えば'INNER JOIN BlockModel AS bm ON b.BlockModel.exist('。[@ id = sql:column( "bm.Block_Model_Id") ')= 1 ' – ZLK

+0

ああ、説明のおかげで、私は正方形と混乱していた角かっこ/根の部分。残念ながらパフォーマンスの向上はありません。 – Trent

+0

パフォーマンスの点では、blockmodelテーブルのblock_model_idカラムにインデックスがあるかどうかに大きく左右されます(存在しない場合は、パフォーマンス上の問題が残っていますが、あなたが提供したクエリに基づいてそれに対する明白な理由)。あなたは、参加する価値のある方法でより良いパフォーマンスを得る可能性が高いです。 – ZLK

答えて

0

idをtempテーブルに破棄し、代わりにそのテーブルを使用します。

create table #bm(ID int primary key); 

insert into #bm (ID) 
select T.X.value('@id', 'int') 
from @iBlockModels.nodes('/BlockModels/BlockModel') as T(X); 

select bm.Name, bm.Block_Model_Id 
from dbo.BlockModel as bm 
    inner join #bm as bm2 
    on bm.Block_Model_Id = bm2.id; 

drop table #bm; 
0

あなたのケースでは、違いはありません。 XPath(SomePath)[1]とすると、最初の出現を探して値を返します。 .exist()はまったく同じですが、存在のみをチェックします。あなたの場合、@idに値が必要ですが、この属性が存在するかどうかをチェックするには不十分です...しかし、両方の呼び出しはただちに単一の値(yes/noまたはnumber)で戻ります。

複数の出現がある場合は、相違があります。あなたの質問が憂鬱な場合少なくとも1つの出現はありますか?あなたは何度もそれを読むために持っているので、.exist()は、より速くより.nodes()など

あなたの参加ニーズ@idの値になります。 JOINでは、これは高速にすることはできません。パフォーマンスが非常に重要である場合は、このような何かを試みる場合がありますがありXMLインデックスがありますが、I would not recommend to use them

:任意の挿入時に必要な値を書き出すか

CREATE TRIGGER dbo.InsertUpdate_tmpTest ON tmpTest 
FOR INSERT,UPDATE 
AS 
BEGIN 
    WITH UpdateableCTE AS 
    (
     SELECT t.RefID AS OldValue 
       ,i.YourXml.value(N'/BlockModels[1]/BlockModel[1]/@id',N'int') AS NewValue 
     FROM tmpTest AS t 
     INNER JOIN inserted AS i ON i.ID=t.ID 
    ) 
    UPDATE UpdateableCTE SET OldValue=NewValue; 
END 
GO 
を更新する

CREATE TABLE tmpTest(ID INT IDENTITY,SomeValue VARCHAR(100),YourXml XML,RefId INT); 
GO 

--createトリガーあなたは、インデックス

CREATE INDEX IX_tmpTest_RefId ON tmpTest(RefId); 
GO 

を配置することができます--now

--some挙動は

INSERT INTO tmpTest(SomeValue,YourXml) VALUES 
('This is row 1','<BlockModels><BlockModel id="1"></BlockModel></BlockModels>') --ref 1 
,('This is row 2','<BlockModels><BlockModel id="1"></BlockModel></BlockModels>') --ref 1 
,('This is row 3','<BlockModels><BlockModel id="2"></BlockModel></BlockModels>') --ref 2 
,('This is row 4','<BlockModels><BlockModel id="3"></BlockModel></BlockModels>');--ref 3 
GO 

SELECT * FROM tmpTest; 

UPDATE tmpTest SET YourXml='<BlockModels><BlockModel id="99"></BlockModel></BlockModels>' WHERE ID=4; 

SELECT * FROM tmpTest; 

UPDATE tmpTest SET YourXml='<BlockModels><BlockModel id="0"></BlockModel></BlockModels>' WHERE ID IN(1,2,3); 

SELECT * FROM tmpTest; 

GO 

をテスト--CleanUp

DROP TRIGGER dbo.InsertUpdate_tmpTest; 
DROP TABLE tmpTest; 

この "計算された" 列RefIdが参加する中で非常に高速になります。「計算列」について

: - あなたのケースで - Regrettfullyそれは可能ではない、インデックスと一緒に(どちらも直接を持続していない)計算列を使用するために...

関連する問題