1

「調査」オブジェクトのコレクションを取得し、それらを適切なテーブルに分割するストアド プロシージャがあります。

「Survey」オブジェクトには、「Erosions」と「Spans」という 2 つの子オブジェクトがあります。

以下は、私が使用する可能性のある XML の例です。

<Surveys>
  <Survey>
    <SurveyID>35</SurveyID>
    <CulvertID>5</CulvertID>
    <PRNo>587180</PRNo>
    <MP>5.243</MP>
    <RefMiles>1.500</RefMiles>
    <PtID>ABCGEFGH</PtID>
    <FWVersion>10</FWVersion>
    <SurveyDate>2012-08-27</SurveyDate>
    <FutureComments>7c36fe43-78cb-436e-81cf-f416aa63c8fc</FutureComments>
    <Erosions>
      <Erosion>
        <ID>160</ID>
        <SurveyID>35</SurveyID>
        <Location>Test Erosion - 8/27/2012 - 1:19:04 PM</Location>
      </Erosion>
      <Erosion>
        <ID>161</ID>
        <SurveyID>35</SurveyID>
        <Location>Test Erosion - 8/27/2012 - 1:19:04 PM</Location>
      </Erosion>
    </Erosions>
    <Spans>
      <Span>
        <ID>88</ID>
        <SurveyID>35</SurveyID>
        <Material>Test Span - 8/27/2012 - 1:19:04 PM</Material>
      </Span>
      <Span>
        <ID>89</ID>
        <SurveyID>35</SurveyID>
        <Material>Test Span - 8/27/2012 - 1:19:04 PM</Material>
      </Span>
    </Spans>
  </Survey>
</Surveys>

ストアド プロシージャの定義を次の場所にアップロードしました (大きすぎてここに貼り付けることができません)。 SQL をダウンロード

上記の XML サンプルを送信すると、手順が完了するまでに約 10 秒かかりますが、これは非常に短い XML 文字列だけです。「VARBINARY(MAX)」列のいずれかに値を含むレコードを更新/挿入するには、数分かかる場合があります。

私は本当に Xquery の初心者です...何が間違っていたのかわかりませんが、パフォーマンスはまったくひどいものです。助言がありますか?

ソリューションで編集:

以下の @wBob の提案に従って、ストアド プロシージャ用にこの SQLを作成しました。テーブルの PK をより「正確」に再定義することになりました。生成された int ID の代わりに、実際のデータ フィールドに基づいています。これにより、マージを使用して、取得する必要がある生成された数値の代わりに、実際のデータ値によって定義された外部キーを使用して子オブジェクトを挿入できるようになりました。

4

2 に答える 2

3

私はあなたの(かなり大きな)procを変更してみました。これは原理 (つまり、OUTPUT 句を使用した MERGE) を示すためのサンプル スクリプトであり、それを完成させてテストするのはあなた次第であることを覚えておいてください。たとえば、すべての列が正しく挿入/更新されていることをテストし、データ型を確認し、NULLIF を削除した場所などを確認する必要があります。TRY/CATCH エラーとトランザクション処理も追加します。また、surveyId に基づいて MERGE を実行したことにも注意してください。それが正しいかどうかわかりませんか?

私があなただったら、これを引き受ける前にMERGEOUTPUT句に慣れるのに時間を費やしますが、幸運を祈ります。

完全なテスト リグへのリンクも添付しました。このスクリプトは安全で、tempdb で完全に再実行できます。

ALTER PROCEDURE [dbo].[sp_SaveSurvey]
    @XMLobject XML
AS
BEGIN

    SET NOCOUNT ON

    CREATE TABLE #tmp_survey ( surveyId INT PRIMARY KEY, erosions XML, spans XML )

    BEGIN TRAN

------------------------------------------------------------------------------------------------
-- MERGE dbo.CULV_StreamCrossingSurvey START
------------------------------------------------------------------------------------------------

    SET IDENTITY_INSERT dbo.CULV_StreamCrossingSurvey ON

    ;MERGE dbo.CULV_StreamCrossingSurvey AS target
    USING
    (
    SELECT
        CAST(NULLIF(X.survey.value('(SurveyID/text())[1]', 'VARCHAR(200)'), '') AS INT) AS SurveyID,
        CAST(NULLIF(X.survey.value('(CulvertID/text())[1]', 'VARCHAR(200)'), '') AS INT) AS CulvertID,
        NULLIF(X.survey.value('(County/text())[1]', 'VARCHAR(50)'), '') AS County,
        NULLIF(X.survey.value('(RoadName/text())[1]', 'VARCHAR(50)'), '') AS RoadName,
        CAST(NULLIF(X.survey.value('(PRNo/text())[1]', 'VARCHAR(50)'), '') AS INT) AS PRNo,
        CAST(NULLIF(X.survey.value('(MP/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,3)) AS MP,
        CAST(NULLIF(X.survey.value('(RefMiles/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,3)) AS RefMiles,
        NULLIF(X.survey.value('(PtID/text())[1]', 'VARCHAR(8)'), '') AS PtID,
        CAST(NULLIF(X.survey.value('(FWVersion/text())[1]', 'VARCHAR(50)'), '') AS SMALLINT) AS FWVersion,
        CAST(NULLIF(X.survey.value('(Latitude/text())[1]', 'VARCHAR(200)'), '') AS FLOAT) AS Latitude,
        CAST(NULLIF(X.survey.value('(Longitude/text())[1]', 'VARCHAR(200)'), '') AS FLOAT) AS Longitude,
        NULLIF(X.survey.value('(Waterway/text())[1]', 'VARCHAR(50)'), '') AS Waterway,
        NULLIF(X.survey.value('(SiteID/text())[1]', 'VARCHAR(50)'), '') AS SiteID,
        NULLIF(X.survey.value('(Observers/text())[1]', 'VARCHAR(50)'), '') AS Observers,
        CAST(NULLIF(X.survey.value('(SurveyDate/text())[1]', 'VARCHAR(200)'), '') AS DATE) AS SurveyDate,
        NULLIF(X.survey.value('(AdjacentLandowner/text())[1]', 'VARCHAR(MAX)'), '') AS AdjacentLandowner,
        NULLIF(X.survey.value('(LocationComments/text())[1]', 'VARCHAR(MAX)'), '') AS LocationComments,
        CAST(NULLIF(X.survey.value('(CrossingType/text())[1]', 'VARCHAR(50)'), '') AS SMALLINT) AS CrossingType,
        NULLIF(X.survey.value('(StructureShape/text())[1]', 'VARCHAR(50)'), '') AS StructureShape,
        NULLIF(X.survey.value('(InletStructure/text())[1]', 'VARCHAR(50)'), '') AS InletStructure,
        NULLIF(X.survey.value('(OutletStructure/text())[1]', 'VARCHAR(50)'), '') AS OutletStructure,
        NULLIF(X.survey.value('(OutletType/text())[1]', 'VARCHAR(50)'), '') AS OutletType,
        NULLIF(X.survey.value('(SubstrateInStructure/text())[1]', 'VARCHAR(50)'), '') AS SubstrateInStructure,
        NULLIF(X.survey.value('(GeneralCondition/text())[1]', 'VARCHAR(50)'), '') AS GeneralCondition,
        CAST(NULLIF(X.survey.value('(PluggedPercent/text())[1]', 'VARCHAR(MAX)'), '') AS SMALLINT) AS PluggedPercent,
        NULLIF(X.survey.value('(PluggedLocation/text())[1]', 'VARCHAR(50)'), '') AS PluggedLocation,
        CAST(NULLIF(X.survey.value('(CrushedPercent/text())[1]', 'VARCHAR(50)'), '') AS SMALLINT) AS CrushedPercent,
        NULLIF(X.survey.value('(CrushedLocation/text())[1]', 'VARCHAR(50)'), '') AS CrushedLocation,
        CAST(NULLIF(X.survey.value('(IsRustedThrough/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsRustedThrough,
        NULLIF(X.survey.value('(StructureInterior/text())[1]', 'VARCHAR(50)'), '') AS StructureInterior,
        CAST(NULLIF(X.survey.value('(StructureWaterDepthInlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureWaterDepthInlet,
        CAST(NULLIF(X.survey.value('(StructureWaterDepthOutlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureWaterDepthOutlet,
        CAST(NULLIF(X.survey.value('(StructureEmbeddedDepthInlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureEmbeddedDepthInlet,
        CAST(NULLIF(X.survey.value('(StructureEmbeddedDepthOutlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureEmbeddedDepthOutlet,
        CAST(NULLIF(X.survey.value('(StructureWaterVelocityInlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureWaterVelocityInlet,
        CAST(NULLIF(X.survey.value('(StructureWaterVelocityOutlet/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureWaterVelocityOutlet,
        CAST(NULLIF(X.survey.value('(StructureWaterVelocityMeasured/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS StructureWaterVelocityMeasured,
        NULLIF(X.survey.value('(StructureWaterVelocityMeasuredWith/text())[1]', 'VARCHAR(50)'), '') AS StructureWaterVelocityMeasuredWith,
        CAST(NULLIF(X.survey.value('(IsPerched/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsPerched,
        CAST(NULLIF(X.survey.value('(PerchHeight/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS PerchHeight,
        NULLIF(X.survey.value('(StreamFlow/text())[1]', 'VARCHAR(50)'), '') AS StreamFlow,
        CAST(NULLIF(X.survey.value('(IsScourPoolPresent/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsScourPoolPresent,
        CAST(NULLIF(X.survey.value('(ScourPoolLength/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS ScourPoolLength,
        CAST(NULLIF(X.survey.value('(ScourPoolWidth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS ScourPoolWidth,
        CAST(NULLIF(X.survey.value('(ScourPoolDepth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS ScourPoolDepth,
        CAST(NULLIF(X.survey.value('(IsUpstreamPondPresent/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsUpstreamPondPresent,
        CAST(NULLIF(X.survey.value('(UpstreamPondLength/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS UpstreamPondLength,
        CAST(NULLIF(X.survey.value('(UpstreamPondWidth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS UpstreamPondWidth,
        CAST(NULLIF(X.survey.value('(RiffleWaterDepth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS RiffleWaterDepth,
        CAST(NULLIF(X.survey.value('(RiffleBankfullWidth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS RiffleBankfullWidth,
        CAST(NULLIF(X.survey.value('(RiffleWettedWidth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS RiffleWettedWidth,
        CAST(NULLIF(X.survey.value('(RiffleWaterVelocity/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS RiffleWaterVelocity,
        NULLIF(X.survey.value('(RiffleMeasuredWith/text())[1]', 'VARCHAR(50)'), '') AS RiffleMeasuredWith,
        NULLIF(X.survey.value('(RiffleSubstrate/text())[1]', 'VARCHAR(50)'), '') AS RiffleSubstrate,
        NULLIF(X.survey.value('(RoadSurface/text())[1]', 'VARCHAR(50)'), '') AS RoadSurface,
        NULLIF(X.survey.value('(RoadCondition/text())[1]', 'VARCHAR(50)'), '') AS RoadCondition,
        CAST(NULLIF(X.survey.value('(RoadWidth/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS RoadWidth,
        NULLIF(X.survey.value('(LocationOfLowPoint/text())[1]', 'VARCHAR(50)'), '') AS LocationOfLowPoint,
        NULLIF(X.survey.value('(RunOffPath/text())[1]', 'VARCHAR(50)'), '') AS RunOffPath,
        CAST(NULLIF(X.survey.value('(FillDepthUpStream/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS FillDepthUpStream,
        CAST(NULLIF(X.survey.value('(FillDepthDownStream/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS FillDepthDownStream,
        NULLIF(X.survey.value('(SlopeUpStream/text())[1]', 'VARCHAR(50)'), '') AS SlopeUpStream,
        NULLIF(X.survey.value('(SlopeDownStream/text())[1]', 'VARCHAR(50)'), '') AS SlopeDownStream,
        CAST(NULLIF(X.survey.value('(ApproachLengthLeft/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS ApproachLengthLeft,
        CAST(NULLIF(X.survey.value('(ApproachLengthRight/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(6,1)) AS ApproachLengthRight,
        NULLIF(X.survey.value('(ApproachSlopeLeft/text())[1]', 'VARCHAR(50)'), '') AS ApproachSlopeLeft,
        NULLIF(X.survey.value('(ApproachSlopeRight/text())[1]', 'VARCHAR(50)'), '') AS ApproachSlopeRight,
        NULLIF(X.survey.value('(VegetationDitchLeft/text())[1]', 'VARCHAR(50)'), '') AS VegetationDitchLeft,
        NULLIF(X.survey.value('(VegetationDitchRight/text())[1]', 'VARCHAR(50)'), '') AS VegetationDitchRight,
        CAST(NULLIF(X.survey.value('(IsErosionPresent/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsErosionPresent,
        CAST(NULLIF(X.survey.value('(IsErosionCorrectable/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsErosionCorrectable,
        NULLIF(X.survey.value('(ErosionExtent/text())[1]', 'VARCHAR(50)'), '') AS ErosionExtent,
        NULLIF(X.survey.value('(ErosionNotes/text())[1]', 'VARCHAR(MAX)'), '') AS ErosionNotes,
        CAST(NULLIF(X.survey.value('(IsPrioritySite/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsPrioritySite,
        NULLIF(X.survey.value('(PriorityReason/text())[1]', 'VARCHAR(50)'), '') AS PriorityReason,
        NULLIF(X.survey.value('(PriorityComments/text())[1]', 'VARCHAR(MAX)'), '') AS PriorityComments,
        CAST(NULLIF(X.survey.value('(FutureVisit/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS FutureVisit,
        NULLIF(X.survey.value('(FutureComments/text())[1]', 'VARCHAR(MAX)'), '') AS FutureComments,
        CAST(NULLIF(X.survey.value('(NonNativeInvasiveSpecies/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS NonNativeInvasiveSpecies,
        NULLIF(X.survey.value('(SpeciesObserved/text())[1]', 'VARCHAR(MAX)'), '') AS SpeciesObserved,
        CAST(NULLIF(X.survey.value('(IsHeadChanged/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsHeadChanged,
        NULLIF(X.survey.value('(HeadChangeComments/text())[1]', 'VARCHAR(MAX)'), '') AS HeadChangeComments,
        CAST(NULLIF(X.survey.value('(IsBackwatered/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsBackwatered,
        NULLIF(X.survey.value('(BackwaterComments/text())[1]', 'VARCHAR(MAX)'), '') AS BackwaterComments,
        CAST(NULLIF(X.survey.value('(IsOvertopping/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsOvertopping,
        NULLIF(X.survey.value('(OvertoppingComments/text())[1]', 'VARCHAR(MAX)'), '') AS OvertoppingComments,
        CAST(NULLIF(X.survey.value('(IsSubstrateEntireLength/text())[1]', 'VARCHAR(10)'), '') AS BIT) AS IsSubstrateEntireLength,
        CAST(NULLIF(X.survey.value('(CalculatedPassability/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(4,1)) AS CalculatedPassability,
        CAST(NULLIF(X.survey.value('(DefinedPassability/text())[1]', 'VARCHAR(50)'), '') AS NUMERIC(4,1)) AS DefinedPassability,
        NULLIF(X.survey.value('(PassabilityComments/text())[1]', 'VARCHAR(MAX)'), '') AS PassabilityComments,
        NULLIF(X.survey.value('(PhotoInlet/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoInlet,
        NULLIF(X.survey.value('(PhotoInletFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoInletFileName,
        NULLIF(X.survey.value('(PhotoOutlet/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoOutlet,
        NULLIF(X.survey.value('(PhotoOutletFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoOutletFileName,
        NULLIF(X.survey.value('(PhotoUpstream/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoUpstream,
        NULLIF(X.survey.value('(PhotoUpstreamFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoUpstreamFileName,
        NULLIF(X.survey.value('(PhotoDownstream/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoDownstream,
        NULLIF(X.survey.value('(PhotoDownstreamFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoDownstreamFileName,
        NULLIF(X.survey.value('(PhotoRoadApproachLeft/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoRoadApproachLeft,
        NULLIF(X.survey.value('(PhotoRoadApproachLeftFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoRoadApproachLeftFileName,
        NULLIF(X.survey.value('(PhotoRoadApproachRight/text())[1]', 'VARBINARY(MAX)'), '') AS PhotoRoadApproachRight,
        NULLIF(X.survey.value('(PhotoRoadApproachRightFileName/text())[1]', 'VARCHAR(200)'), '') AS PhotoRoadApproachRightFileName,
        Erosions = (CASE WHEN CAST(X.survey.query('Erosions') AS VARCHAR(MAX)) = '' THEN NULL
        ELSE X.survey.query('Erosions') END),
        Spans = (CASE WHEN CAST(X.survey.query('Spans') AS VARCHAR(MAX)) = '' THEN NULL
        ELSE X.survey.query('Spans') END)
    FROM @XMLobject.nodes('Surveys/Survey') AS X(survey)
    ) AS source ON source.SurveyId = target.SurveyId

    WHEN NOT MATCHED BY TARGET 
        THEN 
        INSERT ( surveyId, CulvertID, County, RoadName, PRNo, MP, RefMiles, PtID, FWVersion, Latitude, Longitude, Waterway, SiteID, Observers, SurveyDate, AdjacentLandowner, LocationComments, CrossingType, StructureShape, InletStructure, OutletStructure, OutletType, SubstrateInStructure, GeneralCondition, PluggedPercent, PluggedLocation, CrushedPercent, CrushedLocation, IsRustedThrough, StructureInterior, StructureWaterDepthInlet, StructureWaterDepthOutlet, StructureEmbeddedDepthInlet, StructureEmbeddedDepthOutlet, StructureWaterVelocityInlet, StructureWaterVelocityOutlet, StructureWaterVelocityMeasured, StructureWaterVelocityMeasuredWith, IsPerched, PerchHeight, StreamFlow, IsScourPoolPresent, ScourPoolLength, ScourPoolWidth, ScourPoolDepth, IsUpstreamPondPresent, UpstreamPondLength, UpstreamPondWidth, RiffleWaterDepth, RiffleBankfullWidth, RiffleWettedWidth, RiffleWaterVelocity, RiffleMeasuredWith, RiffleSubstrate, RoadSurface, RoadCondition, RoadWidth, LocationOfLowPoint, RunOffPath, FillDepthUpStream, FillDepthDownStream, SlopeUpStream, SlopeDownStream, ApproachLengthLeft, ApproachLengthRight, ApproachSlopeLeft, ApproachSlopeRight, VegetationDitchLeft, VegetationDitchRight, IsErosionPresent, IsErosionCorrectable, ErosionExtent, ErosionNotes, IsPrioritySite, PriorityReason, PriorityComments, FutureVisit, FutureComments, NonNativeInvasiveSpecies, SpeciesObserved, IsHeadChanged, HeadChangeComments, IsBackwatered, BackwaterComments, IsOvertopping, OvertoppingComments, IsSubstrateEntireLength, CalculatedPassability, DefinedPassability, PassabilityComments, PhotoInlet, PhotoInletFileName, PhotoOutlet, PhotoOutletFileName, PhotoUpstream, PhotoUpstreamFileName, PhotoDownstream, PhotoDownstreamFileName, PhotoRoadApproachLeft, PhotoRoadApproachLeftFileName, PhotoRoadApproachRight, PhotoRoadApproachRightFileName )
        VALUES ( surveyId, CulvertID, County, RoadName, PRNo, MP, RefMiles, PtID, FWVersion, Latitude, Longitude, Waterway, SiteID, Observers, SurveyDate, AdjacentLandowner, LocationComments, CrossingType, StructureShape, InletStructure, OutletStructure, OutletType, SubstrateInStructure, GeneralCondition, PluggedPercent, PluggedLocation, CrushedPercent, CrushedLocation, IsRustedThrough, StructureInterior, StructureWaterDepthInlet, StructureWaterDepthOutlet, StructureEmbeddedDepthInlet, StructureEmbeddedDepthOutlet, StructureWaterVelocityInlet, StructureWaterVelocityOutlet, StructureWaterVelocityMeasured, StructureWaterVelocityMeasuredWith, IsPerched, PerchHeight, StreamFlow, IsScourPoolPresent, ScourPoolLength, ScourPoolWidth, ScourPoolDepth, IsUpstreamPondPresent, UpstreamPondLength, UpstreamPondWidth, RiffleWaterDepth, RiffleBankfullWidth, RiffleWettedWidth, RiffleWaterVelocity, RiffleMeasuredWith, RiffleSubstrate, RoadSurface, RoadCondition, RoadWidth, LocationOfLowPoint, RunOffPath, FillDepthUpStream, FillDepthDownStream, SlopeUpStream, SlopeDownStream, ApproachLengthLeft, ApproachLengthRight, ApproachSlopeLeft, ApproachSlopeRight, VegetationDitchLeft, VegetationDitchRight, IsErosionPresent, IsErosionCorrectable, ErosionExtent, ErosionNotes, IsPrioritySite, PriorityReason, PriorityComments, FutureVisit, FutureComments, NonNativeInvasiveSpecies, SpeciesObserved, IsHeadChanged, HeadChangeComments, IsBackwatered, BackwaterComments, IsOvertopping, OvertoppingComments, IsSubstrateEntireLength, CalculatedPassability, DefinedPassability, PassabilityComments, PhotoInlet, PhotoInletFileName, PhotoOutlet, PhotoOutletFileName, PhotoUpstream, PhotoUpstreamFileName, PhotoDownstream, PhotoDownstreamFileName, PhotoRoadApproachLeft, PhotoRoadApproachLeftFileName, PhotoRoadApproachRight, PhotoRoadApproachRightFileName )

    WHEN MATCHED
        THEN UPDATE
            SET target.CulvertID = source.CulvertID

    -- DELETE section
    --WHEN NOT MATCHED BY SOURCE 
    --  THEN DELETE

    OUTPUT source.surveyId, source.Erosions, source.Spans INTO #tmp_survey
    --OUTPUT $action
    ;


-- MERGE dbo.CULV_StreamCrossingSurvey END
------------------------------------------------------------------------------------------------



------------------------------------------------------------------------------------------------
-- DELETEs START
-- Remove existing erosion and span records
------------------------------------------------------------------------------------------------

DELETE e
FROM dbo.CULV_StreamCrossingErosion e
    INNER JOIN #tmp_survey s ON e.SurveyID = s.surveyId

DELETE e
FROM dbo.Culvert_StreamCrossingSpan e
    INNER JOIN #tmp_survey s ON e.SurveyID = s.surveyId

-- DELETEs END
------------------------------------------------------------------------------------------------



------------------------------------------------------------------------------------------------
-- MERGE dbo.CULV_StreamCrossingErosion START
------------------------------------------------------------------------------------------------

;MERGE dbo.CULV_StreamCrossingErosion AS target
USING
(
    SELECT
          t.surveyId
        , NULLIF(E.erosion.value('(Location/text())[1]', 'VARCHAR(50)'), '') AS Location
        , E.erosion.value('(Length/text())[1]', 'NUMERIC(6,1)') AS Length
        , E.erosion.value('(Width/text())[1]', 'NUMERIC(6,1)') AS Width
        , E.erosion.value('(Depth/text())[1]', 'NUMERIC(6,1)') AS Depth
        , E.erosion.value('(IsReachingStream/text())[1]', 'BIT') AS IsReachingStream
        , NULLIF(E.erosion.value('(MaterialEroded/text())[1]', 'VARCHAR(50)'), '') AS MaterialEroded
    FROM #tmp_survey t
        CROSS APPLY erosions.nodes('Erosions/Erosion') AS E(erosion)
) AS source ON source.SurveyId = target.SurveyId

WHEN NOT MATCHED BY TARGET 
    THEN 
    INSERT ( surveyId, Location, Length, Width, Depth, IsReachingStream, MaterialEroded )
    VALUES ( surveyId, Location, Length, Width, Depth, IsReachingStream, MaterialEroded )

WHEN MATCHED
    THEN UPDATE
        SET 
        target.Location = source.Location,
        target.Length = source.Length,
        target.Width = source.Width,
        target.Depth = source.Depth,
        target.IsReachingStream = source.IsReachingStream,
        target.MaterialEroded = source.MaterialEroded
;

;MERGE dbo.Culvert_StreamCrossingSpan AS target
USING
(
    SELECT
        t.surveyId,
        S.span.value('(SpanNumber/text())[1]', 'SMALLINT') AS SpanNumber,
        S.span.value('(Length/text())[1]', 'NUMERIC(6,1)') AS Length,
        S.span.value('(Width/text())[1]', 'NUMERIC(6,1)') AS Width,
        S.span.value('(Height/text())[1]', 'NUMERIC(6,1)') AS Height,
        NULLIF( S.span.value('(Material/text())[1]', 'VARCHAR(50)'), '') AS Material
    FROM #tmp_survey t
        CROSS APPLY spans.nodes('Spans/Span') AS S(span)

) AS source ON source.SurveyId = target.SurveyId

WHEN NOT MATCHED BY TARGET 
    THEN 
    INSERT ( surveyID, SpanNumber, Length, Width, Height, Material )
    VALUES ( surveyID, SpanNumber, Length, Width, Height, Material )

WHEN MATCHED
    THEN UPDATE
        SET 
        target.SpanNumber = source.SpanNumber,
        target.Length = source.Length,
        target.Width = source.Width,
        target.Height = source.Height,
        target.Material = source.Material
;

-- MERGE dbo.CULV_StreamCrossingErosion END
------------------------------------------------------------------------------------------------


-- !!TODO Add TRY/CATCH error and transaction handling

COMMIT

RETURN

END
GO
于 2012-09-20T23:30:50.547 に答える
1

私が推奨できるいくつかの変更があります。まず、.query と .value の両方は必要ありません。.query は XML を返すので、XML が必要な場合は .query を使用します。.value はスカラー値を返すため、ここで使用する必要がある値です。

SELECT
    CAST(NULLIF(X.survey.value('(SurveyID/text())[1]', 'VARCHAR(200)'), '') AS INT) AS SurveyID,
    CAST(NULLIF(X.survey.value('(CulvertID/text())[1]', 'VARCHAR(200)'), '') AS INT) AS CulvertID,

また、 text() コンストラクターと 1 つの序数 (上記のように) を追加すると、 hereに従ってより効率的になります。

第二に、カーソルは必要ないと思います。.nodes は結果セットを返すので、一時テーブルに直接シュレッドしてから、メイン テーブルに INSERT / UPDATE / DELETE できます。SQL 2008 以降を使用している場合は、すべての操作を 1 回で行う MERGE を使用できます。勇気があれば、.nodes 結果セットからメイン テーブルに直接 MERGE することもできます。

これらの変更によって必要なパフォーマンスが得られない場合は、OPENXML の使用を検討してください。これは、大規模な XML ドキュメントの場合により高速になることがあります。OPENXML にはよく知られた機能があり、呼び出されたときにサーバーのメモリの最大 1/8 を自動的に使用できることに注意してください。そのため、常に sp_xml_removedocument を呼び出すことを忘れないでください。

これらの変更を行ってみて、どのようになったかお知らせください。

PS 正しい用語「シュレッド」を使用しています。SAX に関する注意事項は無視してください。SQL Server には、XML を断片化するための非常に強力で高速なコンポーネントが組み込まれています。

于 2012-09-19T22:40:08.133 に答える