эффективный способ преобразования XML документа в табличный набор данных в SQL, потому что запрос cross apply xml работает экспоненциально хуже по мере роста xml - PullRequest
1 голос
/ 05 мая 2020

У меня есть документ большого размера XML (50,000-100,000), который нужно проанализировать на Azure SQL, который выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<covid-19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://covid-19.iss.it/XMLSchema/0.1/">
    <pazienti>
        <paziente>
            <codiceRegionalePaziente>0123456789</codiceRegionalePaziente>
            <codiceFiscale/>
            <nome>nomeBulk01</nome>
            <cognome>cognomeBulk01</cognome>
            <dataNascita>1989-12-31</dataNascita>
            <sesso>F</sesso>
            <nazionalita>380</nazionalita>
            <domicilioIndirizzo/>
            <domicilioCap>00019</domicilioCap>
            <domicilioComune>058104</domicilioComune>
            <domicilioProvincia>RM</domicilioProvincia>
            <residenzaIndirizzo/>
            <residenzaCap/>
            <residenzaComune/>
            <residenzaProvincia/>
            <luogoEsposizione>cinema</luogoEsposizione>
            <luogoEsposizioneComune>058047</luogoEsposizioneComune>
            <operatoreSanitario>1</operatoreSanitario>
            <casoIsolato>9</casoIsolato>
            <casoCollegato/>
            <codiceTampone>kkk12345</codiceTampone>
            <dataPrelievo>2020-03-01</dataPrelievo>
            <codLaboratorioAnalisi>999</codLaboratorioAnalisi>
            <sequenzaGenoma>9</sequenzaGenoma>
            <sequenzaInviata>0</sequenzaInviata>
            <dataInizioSintomi>2020-03-01</dataInizioSintomi>
            <codRegione>99</codRegione>
            <patologieCroniche>9</patologieCroniche>
            <tumoriAttivi/>
            <diabeteMellito/>
            <malattieCardiovascolari/>
            <hiv/>
            <malattieRespiratorieCroniche/>
            <malattieRenali/>
            <altreMalattieMetaboliche/>
            <obesitaBmi30e40/>
            <obesitaBmiOltre40/>
            <malattieEpatiche/>
            <malattieCronicheNeurologiche/>
            <altrePatologie/>
            <altrePatologieDescrizione/>
            <note>test caricamento massivo da file xml</note>
            <collocazioni>
                <collocazione>
                    <dataCollocazione>2020-03-01</dataCollocazione>
                    <collocazioneTipo>Ospedale</collocazioneTipo>
                    <ospedaleNSIS>99999999</ospedaleNSIS>
                    <ospedaleReparto>Pneumologia</ospedaleReparto>
                </collocazione>
            </collocazioni>
            <statiClinici>
                <statoClinico>
                    <tipoStatoClinico>Asintomatico</tipoStatoClinico>
                    <dataStatoClinico>2020-03-01</dataStatoClinico>
                    <terapiaInCorso>0</terapiaInCorso>
                    <terapiaDescrizione/>
                    <intubato>0</intubato>
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Lieve</tipoStatoClinico>
                    <dataStatoClinico>2020-03-12</dataStatoClinico>
                    <terapiaInCorso>0</terapiaInCorso>
                    <terapiaDescrizione/>
                    <intubato>0</intubato>
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Critico</tipoStatoClinico>
                    <dataStatoClinico>2020-03-18</dataStatoClinico>
                    <terapiaInCorso>0</terapiaInCorso>
                    <terapiaDescrizione/>
                    <intubato>1</intubato>
                </statoClinico>
            </statiClinici>
        </paziente>
        <paziente>
            <codiceRegionalePaziente>AABB1234567890</codiceRegionalePaziente>
            <codiceFiscale>AAABBB00C11D222E</codiceFiscale>
            <nome>nomeBulk02</nome>
            <cognome>cognomeBulk02</cognome>
            <dataNascita>2000-01-31</dataNascita>
            <sesso>M</sesso>
            <nazionalita>380</nazionalita>
            <domicilioIndirizzo>Via del domicilio</domicilioIndirizzo>
            <domicilioCap>00100</domicilioCap>
            <domicilioComune>058091</domicilioComune>
            <domicilioProvincia>RM</domicilioProvincia>
            <residenzaIndirizzo/>
            <residenzaCap/>
            <residenzaComune/>
            <residenzaProvincia/>
            <luogoEsposizione>centro commerciale</luogoEsposizione>
            <luogoEsposizioneComune>058091</luogoEsposizioneComune>
            <operatoreSanitario>0</operatoreSanitario>
            <casoIsolato>1</casoIsolato>
            <casoCollegato/>
            <codiceTampone>00AABB-CC</codiceTampone>
            <dataPrelievo>2020-02-29</dataPrelievo>
            <codLaboratorioAnalisi>999</codLaboratorioAnalisi>
            <sequenzaGenoma>1</sequenzaGenoma>
            <sequenzaInviata>0</sequenzaInviata>
            <dataInizioSintomi>2020-02-29</dataInizioSintomi>
            <codRegione>99</codRegione>
            <patologieCroniche>1</patologieCroniche>
            <tumoriAttivi>0</tumoriAttivi>
            <diabeteMellito>0</diabeteMellito>
            <malattieCardiovascolari>1</malattieCardiovascolari>
            <hiv>0</hiv>
            <malattieRespiratorieCroniche>1</malattieRespiratorieCroniche>
            <malattieRenali>0</malattieRenali>
            <altreMalattieMetaboliche>0</altreMalattieMetaboliche>
            <obesitaBmi30e40>0</obesitaBmi30e40>
            <obesitaBmiOltre40>0</obesitaBmiOltre40>
            <malattieEpatiche>0</malattieEpatiche>
            <malattieCronicheNeurologiche>0</malattieCronicheNeurologiche>
            <altrePatologie>1</altrePatologie>
            <altrePatologieDescrizione>descrizione altra patologia cronica</altrePatologieDescrizione>
            <note>test caricamento massivo da file xml</note>
            <collocazioni>
                <collocazione>
                    <dataCollocazione>2020-03-01</dataCollocazione>
                    <collocazioneTipo>Domicilio</collocazioneTipo>
                    <ospedaleNSIS/>
                    <ospedaleReparto/>
                </collocazione>
                <collocazione>
                    <dataCollocazione>2020-03-05</dataCollocazione>
                    <collocazioneTipo>Ospedale</collocazioneTipo>
                    <ospedaleNSIS>99999999</ospedaleNSIS>
                    <ospedaleReparto>Malattie infettive e tropicali</ospedaleReparto>
                </collocazione>
            </collocazioni>
            <statiClinici>
                <statoClinico>
                    <tipoStatoClinico>Pauci-sintomatico</tipoStatoClinico>
                    <dataStatoClinico>2020-02-29</dataStatoClinico>
                    <terapiaInCorso>0</terapiaInCorso>
                    <terapiaDescrizione/>
                    <intubato>0</intubato>
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Severo</tipoStatoClinico>
                    <dataStatoClinico>2020-03-17</dataStatoClinico>
                    <terapiaInCorso>1</terapiaInCorso>
                    <terapiaDescrizione>descrizione  della terapia in corso</terapiaDescrizione>
                    <intubato>0</intubato>
                </statoClinico>
            </statiClinici>
        </paziente>
        <paziente>
            <codiceRegionalePaziente>9999999</codiceRegionalePaziente>
            <codiceFiscale/>
            <nome>nomeBulk03</nome>
            <cognome>cognomeBulk03</cognome>
            <dataNascita>2000-01-31</dataNascita>
            <sesso>M</sesso>
            <nazionalita>380</nazionalita>
            <domicilioIndirizzo>Via del domicilio</domicilioIndirizzo>
            <domicilioCap>00100</domicilioCap>
            <domicilioComune>058091</domicilioComune>
            <domicilioProvincia>RM</domicilioProvincia>
            <residenzaIndirizzo/>
            <residenzaCap/>
            <residenzaComune/>
            <residenzaProvincia/>
            <luogoEsposizione>centro commerciale</luogoEsposizione>
            <luogoEsposizioneComune>058091</luogoEsposizioneComune>
            <operatoreSanitario>0</operatoreSanitario>
            <casoIsolato>1</casoIsolato>
            <casoCollegato/>
            <codiceTampone>00AABB-CC</codiceTampone>
            <dataPrelievo>2020-02-29</dataPrelievo>
            <codLaboratorioAnalisi>999</codLaboratorioAnalisi>
            <sequenzaGenoma>1</sequenzaGenoma>
            <sequenzaInviata>0</sequenzaInviata>
            <dataInizioSintomi>2020-02-29</dataInizioSintomi>
            <codRegione>99</codRegione>
            <patologieCroniche>1</patologieCroniche>
            <tumoriAttivi>0</tumoriAttivi>
            <diabeteMellito>0</diabeteMellito>
            <malattieCardiovascolari>1</malattieCardiovascolari>
            <hiv>0</hiv>
            <malattieRespiratorieCroniche>1</malattieRespiratorieCroniche>
            <malattieRenali>0</malattieRenali>
            <altreMalattieMetaboliche>0</altreMalattieMetaboliche>
            <obesitaBmi30e40>0</obesitaBmi30e40>
            <obesitaBmiOltre40>0</obesitaBmiOltre40>
            <malattieEpatiche>0</malattieEpatiche>
            <malattieCronicheNeurologiche>0</malattieCronicheNeurologiche>
            <altrePatologie>1</altrePatologie>
            <altrePatologieDescrizione>descrizione altra patologia cronica</altrePatologieDescrizione>
            <note>test caricamento massivo da file xml</note>
            <collocazioni>
            </collocazioni>
            <statiClinici>
            </statiClinici>
        </paziente>
    </pazienti>
</covid-19>

Мне нужно разделить его на 3 набор данных обычного табличного типа (pazienti, collocazioni, statiClinici), и я использую следующий код T- SQL, который работает:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON
DECLARE @StartTime datetime = getdate()
    -- Insert statements for procedure here
    -- DROP temp tables
    if object_id('tempdb..#xmlPazienti') is not null DROP TABLE #xmlPazienti;
    if object_id('tempdb..#xmlCollocazioni') is not null DROP TABLE #xmlCollocazioni;
    if object_id('tempdb..#xmlStatiClinici') is not null DROP TABLE #xmlStatiClinici;

    -- pazienti --
    CREATE TABLE #xmlPazienti
    (
        [patientId] [int] NULL
        ,[codiceFiscale] [varchar](16) NULL
        ,[nome] [nvarchar](255) NULL
        ,[cognome] [nvarchar](255) NULL
        ,[dataNascita] [datetime] NULL
        ,[sesso] [char](1) NULL
        ,[nazionalita] [smallint] NULL
        ,[domicilioInd] [varchar](255) NULL
        ,[domicilioCap] [varchar](10) NULL
        ,[domicilioCom] [varchar](255) NULL
        ,[domicilioProv] [varchar](255) NULL
        ,[residenzaInd] [varchar](255) NULL
        ,[residenzaCap] [varchar](10) NULL
        ,[residenzaCom] [varchar](255) NULL
        ,[residenzaProv] [varchar](255) NULL
        ,[luogoEsp] [nvarchar](500) NULL
        ,[luogoEspCom] [varchar](255) NULL
        ,[operatoreSanitario] [tinyint] NULL
        ,[casoIsolato] [tinyint] NULL
        ,[casoCollegato] [varchar](500) NULL
        ,[CodiceTampone] [varchar](255) NULL
        ,[dataPrelievo] [date] NULL
        ,[LaboratorioAnalisiId] [smallint] NULL
        ,[sequenzaGenoma] [tinyint] NULL
        ,[sequenzaInviata] [tinyint] NULL
        ,[DataInizioSintomi] [date] NULL
        ,[codRegione] [smallint] NULL
        ,[PatologieCroniche] [tinyint] NULL
        ,[TumoriAttivi] [tinyint] NULL
        ,[DiabeteMellito] [tinyint] NULL
        ,[MalattieCardiovascolari] [tinyint] NULL
        ,[HIV] [tinyint] NULL
        ,[MalattieRespiratorieCroniche] [tinyint] NULL
        ,[MalattieRenali] [tinyint] NULL
        ,[AltreMalattieMetaboliche] [tinyint] NULL
        ,[ObesitàBMI30e40] [tinyint] NULL
        ,[ObesitàBMIoltre40] [tinyint] NULL
        ,[MalattieEpatiche] [tinyint] NULL
        ,[MalattieCronicheNeurologiche] [tinyint] NULL
        ,[AltrePatologie] [tinyint] NULL
        ,[AltrePatologieDescrizione] [nvarchar](500) NULL
        ,[Note] [nvarchar](4000) NULL
        ,[patientID_reg] [nvarchar](50) NULL
        ,[flagBaseline] [int] NULL
    )
    -- pazienti --

    -- collocazioni --
    CREATE TABLE #xmlCollocazioni
    (
    dataRicovero date NULL
    ,collocazioneId int NULL
    ,idOspedale nvarchar(255) NULL
    ,CodReparto int NULL
    ,patientID int NULL
    ,patientID_reg nvarchar(50) NULL
    ,collocazioneTipo nvarchar(50) NULL
    ,ospedaleReparto nvarchar(255) NULL
    );
    -- collocazioni --

    -- stati clinici --
    CREATE TABLE #xmlStatiClinici
    (
    patientID int NULL
    ,statoClinicoId int NULL
    ,dataStatoClinico date NULL
    ,terapiaInCorso int NULL
    ,terapia nvarchar(1000) NULL
    ,Intubato int NULL
    ,patientID_reg nvarchar(50) NULL
    ,tipoStatoClinico nvarchar(50) NULL
    );
    -- stati clinici --

    -- index on temp tables --
        CREATE INDEX ixTmp_patient_patientId ON #xmlPazienti (patientId);
        CREATE INDEX ixTmp_patient_patientID_reg ON #xmlPazienti (patientID_reg);
        CREATE INDEX ixTmp_patient_codRegione ON #xmlPazienti (codRegione) INCLUDE (patientId);
        CREATE INDEX ixTmp_patient_LaboratorioAnalisiId ON #xmlPazienti (LaboratorioAnalisiId);
        CREATE INDEX ixTmp_ricovero_patientId ON #xmlCollocazioni (patientId);
        CREATE INDEX ixTmp_ricovero_patientID_reg ON #xmlCollocazioni (patientID_reg);
        CREATE INDEX ixTmp_ricovero_collocazioneID ON #xmlCollocazioni (collocazioneID);
        CREATE INDEX ixTmp_ricovero_idOspedale ON #xmlCollocazioni (idOspedale);
        CREATE INDEX ixTmp_ricovero_codReparto ON #xmlCollocazioni (codReparto);
        CREATE INDEX ixTmp_monitoring_patientId ON #xmlStatiClinici (patientId);
        CREATE INDEX ixTmp_monitoring_patientID_reg ON #xmlStatiClinici (patientID_reg);
        CREATE INDEX ixTmp_monitoring_statoClinicoId ON #xmlStatiClinici (statoClinicoId);
    -- index on temp tables --


DECLARE @StartTimeInsertPazienti datetime = getdate()
DECLARE @fId INT = 187
DECLARE @XML AS XML
SELECT @XML = XMLData FROM XMLbulkLoad WHERE Id = @fId
;WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
    -- pazienti --
    INSERT INTO #xmlPazienti WITH (TABLOCK) ([patientID_reg],[codiceFiscale],[cognome],[nome],[dataNascita],[sesso],[nazionalita],[domicilioInd],[domicilioCap],[domicilioCom],[domicilioProv],[residenzaInd],[residenzaCap],[residenzaCom],[residenzaProv],[luogoEsp],[luogoEspCom],[operatoreSanitario],[casoIsolato],[casoCollegato],[CodiceTampone],[dataPrelievo],[LaboratorioAnalisiId],[sequenzaGenoma],[sequenzaInviata],[DataInizioSintomi],[codRegione],[PatologieCroniche],[TumoriAttivi],[DiabeteMellito],[MalattieCardiovascolari],[HIV],[MalattieRespiratorieCroniche],[MalattieRenali],[AltreMalattieMetaboliche],[ObesitàBMI30e40],[ObesitàBMIoltre40],[MalattieEpatiche],[MalattieCronicheNeurologiche],[AltrePatologie],[AltrePatologieDescrizione],[Note])
    SELECT   ISNULL(paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)'),NULL) AS [patientID_reg]  
            ,ISNULL(paz.value('(codiceFiscale/text())[1]', 'varchar(16)'),NULL) AS [codiceFiscale]
            ,ISNULL(paz.value('(cognome/text())[1]', 'nvarchar(255)'),NULL) AS [cognome]
            ,ISNULL(paz.value('(nome/text())[1]', 'nvarchar(255)'),NULL) AS [nome]
            ,ISNULL(paz.value('(dataNascita/text())[1]', 'datetime'),NULL) AS [dataNascita]
            ,ISNULL(paz.value('(sesso/text())[1]', 'char(1)'),NULL) AS [sesso]
            ,ISNULL(paz.value('(nazionalita/text())[1]', 'smallint'),NULL) AS [nazionalita]
            ,ISNULL(paz.value('(domicilioIndirizzo/text())[1]', 'varchar(255)'),NULL) AS [domicilioInd]
            ,ISNULL(paz.value('(domicilioCap/text())[1]', 'varchar(10)'),NULL) AS [domicilioCap]
            ,ISNULL(paz.value('(domicilioComune/text())[1]', 'varchar(255)'),NULL) AS [domicilioCom]
            ,ISNULL(paz.value('(domicilioProvincia/text())[1]', 'varchar(255)'),NULL) AS [domicilioProv]
            ,ISNULL(paz.value('(residenzaIndirizzo/text())[1]', 'varchar(255)'),NULL) AS [residenzaInd]
            ,ISNULL(paz.value('(residenzaCap/text())[1]', 'varchar(10)'),NULL) AS [residenzaCap]
            ,ISNULL(paz.value('(residenzaComune/text())[1]', 'varchar(255)'),NULL) AS [residenzaCom]
            ,ISNULL(paz.value('(residenzaProvincia/text())[1]', 'varchar(255)'),NULL) AS [residenzaProv]
            ,ISNULL(paz.value('(luogoEsposizione/text())[1]', 'nvarchar(500)'),NULL) AS [luogoEsp]
            ,ISNULL(paz.value('(luogoEsposizioneComune/text())[1]', 'varchar(255)'),NULL) AS [luogoEspCom]
            ,ISNULL(paz.value('(operatoreSanitario/text())[1]', 'tinyint'),NULL) AS [operatoreSanitario]
            ,ISNULL(paz.value('(casoIsolato/text())[1]', 'tinyint'),NULL) AS [casoIsolato]
            ,ISNULL(paz.value('(casoCollegato/text())[1]', 'varchar(500)'),NULL) AS [casoCollegato]
            ,ISNULL(paz.value('(codiceTampone/text())[1]', 'varchar(255)'),NULL) AS [CodiceTampone]
            ,ISNULL(paz.value('(dataPrelievo/text())[1]', 'date'),NULL) AS [dataPrelievo]
            ,ISNULL(paz.value('(codLaboratorioAnalisi/text())[1]', 'smallint'),NULL) AS [LaboratorioAnalisiId]
            ,ISNULL(paz.value('(sequenzaGenoma/text())[1]', 'tinyint'),NULL) AS [sequenzaGenoma]
            ,ISNULL(paz.value('(sequenzaInviata/text())[1]', 'tinyint'),NULL) AS [sequenzaInviata]
            ,ISNULL(paz.value('(dataInizioSintomi/text())[1]', 'date'),NULL) AS [dataInizioSintomi]
            ,ISNULL(paz.value('(codRegione/text())[1]', 'smallint'),'') AS [codRegione]
            ,ISNULL(paz.value('(patologieCroniche/text())[1]', 'tinyint'),NULL) AS [patologieCroniche]
            ,ISNULL(paz.value('(tumoriAttivi/text())[1]', 'tinyint'),NULL) AS [tumoriAttivi]
            ,ISNULL(paz.value('(diabeteMellito/text())[1]', 'tinyint'),NULL) AS [diabeteMellito]
            ,ISNULL(paz.value('(malattieCardiovascolari/text())[1]', 'tinyint'),NULL) AS [malattieCardiovascolari]
            ,ISNULL(paz.value('(hiv/text())[1]', 'tinyint'),NULL) AS [hiv]
            ,ISNULL(paz.value('(malattieRespiratorieCroniche/text())[1]', 'tinyint'),NULL) AS [malattieRespiratorieCroniche]
            ,ISNULL(paz.value('(malattieRenali/text())[1]', 'tinyint'),NULL) AS [malattieRenali]
            ,ISNULL(paz.value('(altreMalattieMetaboliche/text())[1]', 'tinyint'),NULL) AS [altreMalattieMetaboliche]
            ,ISNULL(paz.value('(obesitaBmi30e40/text())[1]', 'tinyint'),NULL) AS [ObesitàBMI30e40]
            ,ISNULL(paz.value('(obesitaBmiOltre40/text())[1]', 'tinyint'),NULL) AS [ObesitàBMIoltre40]
            ,ISNULL(paz.value('(malattieEpatiche/text())[1]', 'tinyint'),NULL) AS [malattieEpatiche]
            ,ISNULL(paz.value('(malattieCronicheNeurologiche/text())[1]', 'tinyint'),NULL) AS [malattieCronicheNeurologiche]
            ,ISNULL(paz.value('(altrePatologie/text())[1]', 'tinyint'),NULL) AS [altrePatologie]
            ,ISNULL(paz.value('(altrePatologieDescrizione/text())[1]', 'nvarchar(500)'),NULL) AS [altrePatologieDescrizione]
            ,ISNULL(paz.value('(note/text())[1]', 'nvarchar(4000)'),NULL) AS [note]
    FROM  
         @XML.nodes('covid-19/pazienti/paziente') AS A(paz)
         --OPTION (OPTIMIZE FOR UNKNOWN)
         --OPTION (RECOMPILE)
    -- pazienti --
DECLARE @EndTimeInsertPazienti datetime = getdate()
SELECT DATEDIFF (SS ,@StartTimeInsertPazienti,@EndTimeInsertPazienti) AS PazientiInsertDuration

DECLARE @StartTimeInsertCollocazioni datetime = getdate()
    -- collocazioni --
    --SELECT @XML = XMLData FROM XMLbulkLoadDEV WHERE Id = @fID
    --;WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
    INSERT INTO #xmlCollocazioni WITH (TABLOCK) (patientID_reg, dataRicovero, collocazioneTipo, idOspedale, ospedaleReparto)
    SELECT  COALESCE(paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)'),NULL) AS [patientID_reg]      
            ,COALESCE(coll.value('(dataCollocazione/text())[1]', 'date'),NULL) AS [dataRicovero]
            ,COALESCE(coll.value('(collocazioneTipo/text())[1]', 'nvarchar(50)'),NULL) AS [collocazioneTipo]
            ,COALESCE(coll.value('(ospedaleNSIS/text())[1]', 'nvarchar(255)'),NULL) AS [idOspedale]
            ,COALESCE(coll.value('(ospedaleReparto/text())[1]', 'nvarchar(255)'),NULL) AS [ospedaleReparto]
    FROM  
         @XML.nodes('covid-19/pazienti/paziente') AS A(paz) 
     OUTER APPLY 
         paz.nodes('collocazioni/collocazione') B(coll)
         --OPTION (OPTIMIZE FOR UNKNOWN)
         --OPTION (RECOMPILE)
    -- collocazioni --
DECLARE @EndTimeInsertCollocazioni datetime = getdate()
SELECT DATEDIFF (SS ,@StartTimeInsertCollocazioni,@EndTimeInsertCollocazioni) AS CollocazioniInsertDuration

DECLARE @StarTimeInsertStatiClinici datetime = getdate()

    -- stati clinici --
    --SELECT @XML = XMLData FROM XMLbulkLoadDEV WHERE Id = @fID
    --;WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
    INSERT INTO #xmlStatiClinici WITH (TABLOCK) (patientID_reg, tipoStatoClinico, dataStatoClinico, terapiaInCorso, terapia, intubato)
    SELECT   ISNULL(paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)'),NULL) AS [patientID_reg]      
            ,ISNULL(sc.value('(tipoStatoClinico/text())[1]', 'nvarchar(50)'),NULL) AS [tipoStatoClinico]
            ,ISNULL(sc.value('(dataStatoClinico/text())[1]', 'date'),NULL) AS [dataStatoClinico]
            ,ISNULL(sc.value('(terapiaInCorso/text())[1]', 'int'),0) AS [terapiaInCorso]
            ,ISNULL(sc.value('(terapiaDescrizione/text())[1]', 'nvarchar(1000)'),NULL) AS [terapia]
            ,ISNULL(sc.value('(intubato/text())[1]', 'int'),NULL) AS [intubato]
    FROM  
         @XML.nodes('covid-19/pazienti/paziente') AS A(paz) 
     OUTER APPLY 
         paz.nodes('statiClinici/statoClinico') C(sc)
        --OPTION (OPTIMIZE FOR UNKNOWN)
        --OPTION (RECOMPILE)
    -- stati clinici --
DECLARE @EndTimeInsertStatiClinici datetime = getdate()
SELECT DATEDIFF (SS ,@StarTimeInsertStatiClinici,@EndTimeInsertStatiClinici) AS StatiCliniciInsertDuration
    --
    --select * from XMLbulkLoad

DECLARE @EndTimeInsert datetime = getdate()
SELECT DATEDIFF (SS ,@StartTimeInsertPazienti,@EndTimeInsertStatiClinici) AS TotalInsertDuration

    -- DROP temp tables
    if object_id('tempdb..#xmlPazienti') is not null DROP TABLE #xmlPazienti;
    if object_id('tempdb..#xmlCollocazioni') is not null DROP TABLE #xmlCollocazioni;
    if object_id('tempdb..#xmlStatiClinici') is not null DROP TABLE #xmlStatiClinici;

Проблема в том, что когда есть несколько сотен (или меньше) элементов в XML, запрос выполняется нормально. Однако, когда есть 25 000 элементов, требуется 50 секунд для завершения sh возврата строк в SSMS, и у меня может быть 50–100 000 элементов.

Есть ли более эффективный способ преобразования документа XML в табличный набор данных (в SQL)?

1 Ответ

0 голосов
/ 06 мая 2020

Один общий совет может быть таким: создайте индексы в качестве последнего шага. Особенно с большим количеством строк это замедлит любые манипуляции с данными (в данном случае ваши операторы вставки);

Как указано в моем комментарии, вы можете пройти по промежуточному маршруту .

Сначала я создаю таблицу-макет для моделирования вашей проблемы

DECLARE @tbl TABLE(YourXML XML);
INSERT INTO @tbl VALUES
(N'<covid-19 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://covid-19.iss.it/XMLSchema/0.1/">
    <pazienti>
        <paziente>
            <codiceRegionalePaziente>0123456789</codiceRegionalePaziente>
            <codiceFiscale/>
            <nome>nomeBulk01</nome>
            <cognome>cognomeBulk01</cognome>
            <!-- shortened -->
            <collocazioni>
                <collocazione>
                    <dataCollocazione>2020-03-01</dataCollocazione>
                    <!-- shortened -->
                </collocazione>
            </collocazioni>
            <statiClinici>
                <statoClinico>
                    <tipoStatoClinico>Asintomatico</tipoStatoClinico>
                    <!-- shortened -->
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Lieve</tipoStatoClinico>
                    <!-- shortened -->
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Critico</tipoStatoClinico>
                    <!-- shortened -->
                </statoClinico>
            </statiClinici>
        </paziente>
        <paziente>
            <codiceRegionalePaziente>AABB1234567890</codiceRegionalePaziente>
            <codiceFiscale>AAABBB00C11D222E</codiceFiscale>
            <nome>nomeBulk02</nome>
            <cognome>cognomeBulk02</cognome>
            <!-- shortened -->
            <collocazioni>
                <collocazione>
                    <dataCollocazione>2020-03-01</dataCollocazione>
                    <!-- shortened -->
                </collocazione>
                <collocazione>
                    <dataCollocazione>2020-03-05</dataCollocazione>
                    <!-- shortened -->
                </collocazione>
            </collocazioni>
            <statiClinici>
                <statoClinico>
                    <tipoStatoClinico>Pauci-sintomatico</tipoStatoClinico>
                    <!-- shortened -->
                </statoClinico>
                <statoClinico>
                    <tipoStatoClinico>Severo</tipoStatoClinico>
                    <!-- shortened -->
                </statoClinico>
            </statiClinici>
        </paziente>
        <paziente>
            <codiceRegionalePaziente>9999999</codiceRegionalePaziente>
            <codiceFiscale/>
            <nome>nomeBulk03</nome>
            <cognome>cognomeBulk03</cognome>
            <!-- shortened -->
            <collocazioni>
            </collocazioni>
            <statiClinici>
            </statiClinici>
        </paziente>
    </pazienti>
</covid-19>');

- Запрос

WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
SELECT   paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)') AS [patientID_reg]  
        ,paz.value('(codiceFiscale/text())[1]', 'varchar(16)') AS [codiceFiscale]
        ,paz.value('(cognome/text())[1]', 'nvarchar(255)') AS [cognome]
        ,paz.value('(nome/text())[1]', 'nvarchar(255)') AS [nome]
        --shortended

        ,coll.value('(dataCollocazione/text())[1]', 'date') AS [dataRicovero]
        --shortended

        ,sc.value('(tipoStatoClinico/text())[1]', 'nvarchar(50)') AS [tipoStatoClinico]
        --shortended

 --Define a target staging table simply automatically
 INTO #StagingTable

 FROM @tbl t
 CROSS APPLY t.YourXML.nodes('covid-19/pazienti/paziente') AS A(paz)
 OUTER APPLY 
     paz.nodes('collocazioni/collocazione') B(coll)

 OUTER APPLY 
     paz.nodes('statiClinici/statoClinico') C(sc);

- теперь все ваши данные сдвинуты в один большая таблица

SELECT * FROM #StagingTable

- используйте что-то вроде этого, чтобы получить данные пациента

SELECT patientID_reg,codiceFiscale,cognome,nome /*all patient related columns*/ 
FROM #StagingTable 
GROUP BY patientID_reg,codiceFiscale,cognome,nome /*all patient related columns*/;

- Это будут ваши связанные данные.

SELECT patientID_reg,dataRicovero /*all collocazioni related data*/ 
FROM #StagingTable 
GROUP BY patientID_reg,dataRicovero /*all collocazioni related data*/

SELECT patientID_reg,tipoStatoClinico /*all stati clinici related data*/ 
FROM #StagingTable 
GROUP BY patientID_reg,tipoStatoClinico /*all stati clinici related data*/

Вы можете выполнить любую очистку или проверку бизнес-логи c на соответствие подготовленным данным. Было бы неплохо проверить существующие patientID_reg значения в вашей целевой таблице ...
Затем перенесите очищенные данные в ваши окончательные целевые таблицы.

ОБНОВЛЕНИЕ

Внимание: Если ваш XML может иметь одинаковое значение patientID_reg для разных элементов, вам нужно будет добавить ROW_NUMBER()

В этом случае вы можете использовать что-то вроде этого:

WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
,ReadPatientDataWithRowNumber AS
(
    SELECT   ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PatientNumber
            ,paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)') AS [patientID_reg]  
            ,paz.value('(codiceFiscale/text())[1]', 'varchar(16)') AS [codiceFiscale]
            ,paz.value('(cognome/text())[1]', 'nvarchar(255)') AS [cognome]
            ,paz.value('(nome/text())[1]', 'nvarchar(255)') AS [nome]
            --shortended
            ,paz.query('collocazioni/collocazione') AS CollocazioneXml
            ,paz.query('statiClinici/statoClinico') AS StatoClinicoXml
     FROM @tbl t
     CROSS APPLY t.YourXML.nodes('covid-19/pazienti/paziente') AS A(paz)
)
,AddTheRest AS
(
    SELECT pd.*

    ,coll.value('(dataCollocazione/text())[1]', 'date') AS [dataRicovero]
    --shortended

    ,sc.value('(tipoStatoClinico/text())[1]', 'nvarchar(50)') AS [tipoStatoClinico]
    --shortended

    FROM ReadPatientDataWithRowNumber pd
     OUTER APPLY 
         pd.CollocazioneXml.nodes('collocazioni/collocazione') B(coll)

     OUTER APPLY 
         pd.StatoClinicoXml.nodes('statiClinici/statoClinico') C(sc)
)   
SELECT * 
INTO #StagingTable
FROM AddTheRest


SELECT PatientNumber,patientID_reg,codiceFiscale,cognome,nome /*all patient related columns*/ 
FROM #StagingTable 
GROUP BY PatientNumber,patientID_reg,codiceFiscale,cognome,nome /*all patient related columns*/;

SELECT PatientNumber,patientID_reg,dataRicovero /*all collocazioni related data*/ 
FROM #StagingTable 
GROUP BY PatientNumber,patientID_reg,dataRicovero /*all collocazioni related data*/

SELECT PatientNumber,patientID_reg,tipoStatoClinico /*all stati clinici related data*/ 
FROM #StagingTable 
GROUP BY PatientNumber,patientID_reg,tipoStatoClinico /*all stati clinici related data*/

ОБНОВЛЕНИЕ 2

Пожалуйста, проверьте это:

WITH XMLNAMESPACES(DEFAULT 'http://covid-19.iss.it/XMLSchema/0.1/')
,ReadPatientDataWithRowNumber AS
(
    SELECT   ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PatientNumber
            ,paz.value('(codiceRegionalePaziente/text())[1]', 'nvarchar(50)') AS [patientID_reg]  
            ,paz.value('(codiceFiscale/text())[1]', 'varchar(16)') AS [codiceFiscale]
            ,paz.value('(cognome/text())[1]', 'nvarchar(255)') AS [cognome]
            ,paz.value('(nome/text())[1]', 'nvarchar(255)') AS [nome]
            --shortended
            ,paz.query('collocazioni/collocazione') AS CollocazioneXml
            ,paz.query('statiClinici/statoClinico') AS StatoClinicoXml
     FROM @tbl t
     CROSS APPLY t.YourXML.nodes('covid-19/pazienti/paziente') AS A(paz)
)
SELECT * 
INTO #StagingTable
FROM ReadPatientDataWithRowNumber

SELECT * FROM #StagingTable;
...