2008-09-14 10 views
24

विभिन्न डेटाबेस कॉलम में XML डेटा को श्रेय देने का सबसे अच्छा तरीका क्या है? अब तक मैं मुख्य रूप से तो जैसे नोड्स और मूल्य कार्यों का उपयोग कर रहे हैं:SQL सर्वर डेटाबेस कॉलम में XML डेटा को श्रेय देने का सबसे अच्छा तरीका

INSERT INTO some_table (column1, column2, column3) 
SELECT 
Rows.n.value('(@column1)[1]', 'varchar(20)'), 
Rows.n.value('(@column2)[1]', 'nvarchar(100)'), 
Rows.n.value('(@column3)[1]', 'int'), 
FROM @xml.nodes('//Rows') Rows(n) 

हालांकि मुझे लगता है कि यह भी मध्यम आकार एक्सएमएल डेटा के लिए बहुत धीमी गति से हो रही है।

+1

हो सकता है कि यदि आप "मध्यम आकार" और वास्तविक संख्या के साथ "धीमी" मात्रा निर्धारित तो लोगों को बेहतर सलाह देने के लिए सक्षम हो जाएगा? –

+0

मॉडरेट> 300 - 500 नोड्स एक बार – eddiegroves

उत्तर

46

एक ही समस्या होने के दौरान इस प्रश्न में ठोकर खाई, मैं आखिरकार छोड़ने से पहले लगभग 3.5 ~ 4 घंटे के लिए एक 7.5 एमबी एक्सएमएल फ़ाइल (~ लगभग 10,000 नोड्स) प्रसंस्करण कर रहा था।

हालांकि, थोड़ा और शोध के बाद मैंने पाया कि एक स्कीमा का उपयोग करके एक्सएमएल टाइप किया है और एक एक्सएमएल इंडेक्स (मैं एक टेबल में थोक डाला गया था) बनाया है, वही क्वेरी ~ 0.04ms में पूरी हुई है।

प्रदर्शन सुधार के लिए यह कैसा है! सूचकांक बनाने के लिए

CREATE PRIMARY XML INDEX PXML_Data 
ON [dbo].[XmlFiles] (Data) 

वहाँ कुछ ही रहे हैं

CREATE TABLE [dbo].[XmlFiles] (
    [Id] [uniqueidentifier] NOT NULL, 

    -- Data from CV element 
    [Data] xml(CONTENT dbo.[MyXmlSchema]) NOT NULL, 

CONSTRAINT [PK_XmlFiles] PRIMARY KEY NONCLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

कोड: एक टाइप एक्सएमएल स्तंभ के साथ तालिका बनाने के लिए

IF EXISTS (SELECT * FROM sys.xml_schema_collections where [name] = 'MyXmlSchema') 
DROP XML SCHEMA COLLECTION [MyXmlSchema] 
GO 

DECLARE @MySchema XML 
SET @MySchema = 
(
    SELECT * FROM OPENROWSET 
    (
     BULK 'C:\Path\To\Schema\MySchema.xsd', SINGLE_CLOB 
    ) AS xmlData 
) 

CREATE XML SCHEMA COLLECTION [MyXmlSchema] AS @MySchema 
GO 

कोड:

कोड एक स्कीमा बनाने के लिए चीजों को ध्यान में रखना हालांकि। स्कीमा का SQL सर्वर का कार्यान्वयन xsd का समर्थन नहीं करता है: शामिल करें। इसका अर्थ यह है कि यदि आपके पास एक स्कीमा है जो अन्य स्कीमा का संदर्भ देती है, तो आपको इन सभी को एक स्कीमा में कॉपी करना होगा और उसे जोड़ना होगा।

इसके अलावा, मैं एक त्रुटि प्राप्त होगा:

XQuery [dbo.XmlFiles.Data.value()]: Cannot implicitly atomize or apply 'fn:data()' to complex content elements, found type 'xs:anyType' within inferred type 'element({http://www.mynamespace.fake/schemas}:SequenceNumber,xs:anyType) ?'. 

अगर मैं नोड मैं नोड समारोह के साथ चुना था ऊपर से नेविगेट करने की कोशिश की। जैसे

SELECT 
    ,C.value('CVElementId[1]', 'INT') AS [CVElementId] 
    ,C.value('../SequenceNumber[1]', 'INT') AS [Level] 
FROM 
    [dbo].[XmlFiles] 
CROSS APPLY 
    [Data].nodes('/CVSet/Level/CVElement') AS T(C) 

मिला सबसे अच्छा तरीका है संभाल करने के लिए है कि इस बाहरी प्रभाव में करने के लिए लागू उपयोग करने के लिए था एक एक्सएमएल पर "बाहरी में शामिल होने के" प्रदर्शन करते हैं।

SELECT 
    ,C.value('CVElementId[1]', 'INT') AS [CVElementId] 
    ,B.value('SequenceNumber[1]', 'INT') AS [Level] 
FROM 
    [dbo].[XmlFiles] 
CROSS APPLY 
    [Data].nodes('/CVSet/Level') AS T(B) 
OUTER APPLY 
    B.nodes ('CVElement') AS S(C) 

आशा है कि इससे किसी को भी मदद मिलेगी क्योंकि यह मेरा दिन बहुत सुंदर रहा है।

+0

ग्रेट उत्तर डैन, क्या आप विस्तार से बता सकते हैं कि आप टेबल में एक्सएमएल नोड्स को कॉलम में कैसे मैप करते हैं? – longhairedsi

+0

अरे लांगहार्डसी, मुझे यकीन नहीं है कि मैंने आपके प्रश्न को सही ढंग से समझा है। क्या आपका मतलब है कि एक्सएमएल दस्तावेज़ के विशिष्ट हिस्सों को टेबल कॉलम में डालना या जैसा कि मैंने पूरे दस्तावेज़ को एक कॉलम में डालने के बाद उपरोक्त है और फिर डेटा प्राप्त करने के लिए एक चयन कथन और .nodes और .value फ़ंक्शंस (और xpath वाक्यविन्यास) का उपयोग करना है एक सारणीबद्ध प्रारूप में बाहर? – Dan

+0

मुझे लगता है कि मैंने आपका जवाब समझा होगा :) मैंने सोचा था कि आप मौजूदा तालिका कॉलम (जैसे XmlFiles.Data से xxx में शामिल) से पहले किसी XML को एक अस्थायी स्थान के रूप में एक कॉलम में जोड़ रहे थे। मैं मौजूदा कॉलम में एक्सएमएल को घुमाने के लिए सबसे अधिक प्रदर्शन करने वाला तरीका ढूंढ रहा था, मुझे लगता है कि थोड़ा सा काम करने से आपका समाधान अच्छी तरह से काम करेगा। – longhairedsi

3

मुझे यकीन नहीं है कि सबसे अच्छी विधि क्या है। मैंने OPENXML निर्माण का उपयोग किया:

INSERT INTO Test 
SELECT Id, Data 
FROM OPENXML (@XmlDocument, '/Root/blah',2) 
WITH (Id int   '@ID', 
     Data varchar(10) '@DATA') 

इसे गति देने के लिए, आप एक्सएमएल इंडेक्स बना सकते हैं। आप विशेष रूप से मान फ़ंक्शन प्रदर्शन अनुकूलन के लिए इंडेक्स सेट कर सकते हैं। इसके अलावा आप टाइप किए गए एक्सएमएल कॉलम का उपयोग कर सकते हैं, जो बेहतर प्रदर्शन करता है।

+0

एस्पो, सुधार के लिए धन्यवाद। मेरी अंग्रेजी बहुत बेकार है। – aku

0

यह कोई जवाब नहीं है, इस प्रश्न के अतिरिक्त - मैं अभी भी एक ही समस्या में आया हूं और मैं आंकड़े दे सकता हूं क्योंकि एडीजी टिप्पणी में पूछता है।

मेरे परीक्षण में एक्सएमएल है जिसके परिणामस्वरूप 244 रिकॉर्ड डाले जा रहे हैं - इसलिए 244 नोड्स।

जो कोड मैं पुनर्लेखन कर रहा हूं वह औसत 0.4 सेकंड तक चलता है। (10 परीक्षण चलते हैं, 56 सेकंड से .344 सेकेंड तक फैले होते हैं) प्रदर्शन मुख्य कारण नहीं है कि कोड को फिर से लिखा जा रहा है, लेकिन नए कोड की ज़रूरत है साथ ही बेहतर प्रदर्शन करने के लिए। यह पुराना कोड एक्सएमएल नोड्स को लूप करता है, एक बार प्रति लूप

नया कोड केवल एक ही एसपी है; एक्सएमएल पास करें; इसके टुकड़ें करें।

नए कोड के साथ टेस्ट में दिखाया गया नया स्पॉट औसत 3.7 सेकेंड पर लेता है - लगभग 10 गुना धीमा।

मेरी क्वेरी इस प्रश्न में पोस्ट किए गए फॉर्म में है;

INSERT INTO some_table (column1, column2, column3) 
SELECT 
Rows.n.value('(@column1)[1]', 'varchar(20)'), 
Rows.n.value('(@column2)[1]', 'nvarchar(100)'), 
Rows.n.value('(@column3)[1]', 'int'), 
FROM @xml.nodes('//Rows') Rows(n) 

कार्य योजना लागू करके दिखाने के लिए कि प्रत्येक स्तंभ के लिए प्रकट होता है, एसक्यूएल सर्वर एक अलग "तालिका मूल्य समारोह [XMLReader]" सभी 244 पंक्तियों लौटने, सभी वापस नेस्टेड लूप्स के साथ शामिल होने के क्या कर रहा है (इनर शामिल हों)। तो मेरे मामले में जहां मैं लगभग 30 कॉलम में घुमा रहा/डाल रहा हूं, ऐसा लगता है कि यह 30 बार अलग होता है।

मुझे इस कोड को डंप करना होगा, मुझे नहीं लगता कि इस विधि को स्वाभाविक रूप से धीमा होने पर कोई अनुकूलन प्राप्त हो रहा है। मैं sp_xml_preparedocument/OPENXML विधि को आजमा रहा हूं और देख सकता हूं कि उसके लिए प्रदर्शन बेहतर है या नहीं। किसी को भी (मैंने किया था के रूप में) एक वेब खोज से यह सवाल भर आता है अगर मैं तुम्हें एसक्यूएल सर्वर में टुकड़ों के इस प्रकार उपयोग करने से पहले कुछ प्रदर्शन परीक्षण करना अत्यधिक सलाह देंगे

+0

यहां दिलचस्प जानकारी है, लेकिन इसे दफनाया गया है। यदि आप अभी भी इसके बारे में हैं, तो इसे एक नए प्रश्न के रूप में पोस्ट करें (और यदि आपको कोई अच्छा समाधान मिल गया है या समस्या की पहचान की गई है तो इसे स्वयं उत्तर दें :-) –

+0

यह स्वयं उत्तर नहीं है बल्कि मूल प्रश्न की पुष्टि है। मूल पोस्टर प्रश्न पर टिप्पणी के माध्यम से कृपया अपना प्रश्न पोस्ट करें और इसके बजाय अपने प्रश्न से लिंक करें। – jpierson

+0

@pst हाय, हाँ अभी भी। धन्यवाद, यह वही है जहां तक ​​मुझे इसके साथ जाने की ज़रूरत है इसलिए मुझे इसे दोबारा पोस्ट करने की आवश्यकता नहीं है। – DannykPowell

0

एक XML Bulk load COM ऑब्जेक्ट (.NET Example)

नहीं है

MSDN से:

You can insert XML data into a SQL Server database by using an INSERT statement and the OPENXML function; however, the Bulk Load utility provides better performance when you need to insert large amounts of XML data.

+3

मैं यह डाउन रोड रहा हूं, और मैं इसका सुझाव नहीं दूंगा। हमारी सबसे बड़ी शिकायत यह थी कि एक्सएमएल थोक लोड लेनदेन संबंधी संदर्भों के भीतर अच्छा नहीं खेल रहा था। हमने इसे काम करने के लिए बहुत अधिक समय बिताया, और अंत में, यह इसका मुख्य हिस्सा है कि यह इसके लायक नहीं है। – Didaxis

0

मेरे बड़े XML सेट (> 500 नोड्स) के लिए मौजूदा समाधान स्मृति में और फिर XML लोड करने के लिए एक डेटासेट का उपयोग करके एसक्यूएल थोक कॉपी (System.Data.SqlClient.SqlBulkCopy) का उपयोग करने के लिए है तालिका को SQLLulkCopy में पास करें (एक एक्सएमएल स्कीमा मदद परिभाषित करता है)।

स्पष्ट रूप से डेटासेट का उपयोग करके और पूरे दस्तावेज़ को पहले स्मृति में लोड करने जैसी समस्याएं हैं। मैं भविष्य में आगे बढ़ना चाहता हूं और डेटासेट विधि को बाईपास करने के लिए अपना खुद का आईडीटाइडर लागू करना चाहता हूं लेकिन वर्तमान में डेटासेट नौकरी के लिए "पर्याप्त" है।

मूल रूप से मुझे उस प्रकार के एक्सएमएल श्रेडरिंग के धीमे प्रदर्शन के बारे में मेरे मूल प्रश्न का कोई समाधान नहीं मिला। टाइप किए गए एक्सएमएल प्रश्नों को स्वाभाविक रूप से धीमा या लेन-देन और SQL सर्वर लॉग के साथ कुछ करने के कारण धीमा हो सकता है। मुझे लगता है कि टाइप किए गए एक्सएमएल फ़ंक्शंस को गैर-तुच्छ नोड आकारों पर परिचालन के लिए कभी डिज़ाइन नहीं किया गया था।

एक्सएमएल थोक लोड: मैं इस कोशिश की और यह तेज था, लेकिन मैं मुसीबत 64 बिट वातावरण के तहत काम करने के लिए COM dll हो रही थी और मैं आम तौर पर COM DLLs कि समर्थन बंद हो दिखाई देते हैं से बचने के लिए प्रयास करें।

sp_xml_preparedocument/OPENXML: मैं कभी भी इस सड़क पर नहीं गया, इसलिए यह देखने में दिलचस्पी होगी कि यह कैसा प्रदर्शन करता है।

+0

मुझे लगता है कि मूल समस्या का सबसे संभावित कारण इंडेक्स की कमी थी। यदि, उस एक्सएमएल खंड को सीधे पूछताछ करने के बजाय, आप इसे एक एक्सएमएल टाइप किए गए कॉलम में एक अस्थायी तालिका में डालते हैं, उस कॉलम पर एक इंडेक्स परिभाषित करते हैं और फिर पूछताछ करते हैं, इससे बड़ा अंतर हो सकता है। –

2

मैं दावा नहीं करता कि यह "सर्वश्रेष्ठ" समाधान है, लेकिन मैंने इस सटीक उद्देश्य के लिए एक सामान्य एसक्यूएल सीएलआर प्रक्रिया लिखी है - इसमें "टैब्यूलर" एक्सएमएल संरचना (जैसे एक्सएमएल रॉ के लिए लौटाया गया है) और एक परिणामसेट आउटपुट।

इसे एक्सएमएल में "टेबल" की संरचना के किसी भी अनुकूलन/ज्ञान की आवश्यकता नहीं है, और यह बेहद तेज़/कुशल हो जाता है (हालांकि यह एक डिज़ाइन लक्ष्य नहीं था)। मैंने बस 20 सेकंड के भीतर 25 एमबी (अनियमित) एक्सएमएल वैरिएबल को फेंक दिया, एक सुंदर चौड़ी तालिका की 25,000 पंक्तियों को वापस कर दिया।

आशा इस मदद करता है किसी को: http://architectshack.com/ClrXmlShredder.ashx

+0

+1। –

3

हम एक ऐसी ही यहां मुद्दा था। हमारे डीबीए (एसपी, आप आदमी) ने मेरे कोड पर एक नज़र डाली, सिंटैक्स को थोड़ा झटका लगा, और हमें वह गति मिली जो हम उम्मीद कर रहे थे। यह असामान्य था क्योंकि एक्सएमएल से मेरा चयन बहुत तेज़ था, लेकिन सम्मिलन धीमा था। तो इसके बजाय इस वाक्यविन्यास को आजमाएं:

INSERT INTO some_table (column1, column2, column3) 
    SELECT 
     Rows.n.value(N'(@column1/text())[1]', 'varchar(20)'), 
     Rows.n.value(N'(@column2/text())[1]', 'nvarchar(100)'), 
     Rows.n.value(N'(@column3/text())[1]', 'int') 
    FROM @xml.nodes('//Rows') Rows(n) 

तो पाठ() पैरामीटर निर्दिष्ट करना वास्तव में प्रदर्शन में एक अंतर दिखता है। 'मैंने गलत लिखा होगा - मुझे इसे रोकने दें' से लगभग 2 सेकंड तक 2K पंक्तियों के हमारे डालने को लिया। कच्चे डालने वाले बयान से 2x तेज था जो हम कनेक्शन के माध्यम से चल रहे थे।

5

मेरे मामले में मैं SQL 2005 SP2 (9.0) चला रहा हूं।

एकमात्र चीज जो विकल्प जोड़ने में मदद कर रही थी (ऑप्टिमाइज़ (@your_xml_var = NULL))। स्पष्टीकरण नीचे दिए गए लिंक पर है।

उदाहरण:

INSERT INTO @tbl (Tbl_ID, Name, Value, ParamData) 
SELECT  1, 
    tbl.cols.value('name[1]', 'nvarchar(255)'), 
    tbl.cols.value('value[1]', 'nvarchar(255)'), 
    tbl.cols.query('./paramdata[1]') 
FROM @xml.nodes('//root') as tbl(cols) OPTION (OPTIMIZE FOR (@xml = NULL)) 

https://connect.microsoft.com/SQLServer/feedback/details/562092/an-insert-statement-using-xml-nodes-is-very-very-very-slow-in-sql2008-sp1

+0

यह मेरे लिए बहुत अच्छी तरह से काम करता है। धन्यवाद.. –

संबंधित मुद्दे

 संबंधित मुद्दे