2012-05-22 14 views
7

पर स्थानांतरित करने का सबसे तेज़ तरीका क्या किसी को बाहरी उपयोगिता (यानी बीसीपी) का उपयोग कर के बिना SQL 2008 पर किसी तालिका में डेटा और एक्सेल टेबल (VBA Array) से डेटा प्राप्त करने का सबसे तेज़ तरीका पता है? ध्यान रखें कि मेरे डेटासेट आमतौर पर 6500-15000 पंक्तियां हैं, और लगभग 150-250 कॉलम हैं; और मैं एक स्वचालित वीबीए बैच स्क्रिप्ट के दौरान उनमें से 20-150 स्थानांतरित कर रहा हूं। VBA सरणी मेंएक्सेल टेबल डेटा को SQL 2008R2

विधि 1. पास मेज और (संग्रहीत प्रक्रिया पर भेज दें:

मैं एक एक्सेल तालिका (VBA) एसक्यूएल 2008 तक मैं उन नीचे सूचीबद्ध है से डेटा की बड़ी मात्रा प्राप्त करने के लिए कई तरीके की कोशिश की है एडीओ) - एसक्यूएल को भेजना धीमा है

विधि 2. डिस्कनेक्ट किए गए रिकॉर्डसेट को लोड करें, फिर सिंक करें। - एसक्यूएल बहुत धीमी

विधि 3. तालिका को वीबीए सरणी में रखें, सरणी और concatenate (delimiters का उपयोग करके) लूप हालांकि संग्रहीत प्रक्रिया को भेजें। - एसक्यूएल स्लोव को भेजना, लेकिन विधि 1 या 2. से तेज।

विधि 4. तालिका को वीबीए सरणी में रखें, सरणी और concatenate (delimiters का उपयोग करके) लूप हालांकि एडीओ रिकॉर्डसेट के साथ प्रत्येक पंक्ति रखें .addnew कमांड। - एसक्यूएल को बहुत तेजी से भेजना (विधियों 1-3 से लगभग 20 गुना तेज), लेकिन अब मुझे एक अलग प्रक्रिया का उपयोग करके उस डेटा को विभाजित करने की आवश्यकता होगी, जो महत्वपूर्ण प्रतीक्षा समय जोड़ देगा।

VBA सरणी में विधि 5. रखें मेज, एक्सएमएल में क्रमानुसार, VARCHAR के रूप में जमा की प्रक्रिया करने के लिए भेजने के लिए और संग्रहीत प्रक्रिया में XML निर्दिष्ट करें। एसक्यूएल को --Sending अविश्वसनीय रूप से धीमा (लगभग 100 बार तरीकों 1 या 2 की तुलना में धीमी)

कुछ भी मुझे याद आ रही?

उत्तर

2

कोई एक सबसे तेज़ तरीका है, के रूप में यह कारकों की एक संख्या पर निर्भर है। सुनिश्चित करें कि SQL में अनुक्रमणिका कॉन्फ़िगर और अनुकूलित हैं। इंडेक्स के कई सारे डालने/अद्यतन प्रदर्शन को मार देंगे क्योंकि प्रत्येक डालने को इंडेक्स को अपडेट करने की आवश्यकता होगी। सुनिश्चित करें कि आप केवल डेटाबेस से एक कनेक्शन बनाते हैं, और ऑपरेशन के दौरान इसे खोल/बंद नहीं करते हैं। जब सर्वर न्यूनतम लोड के अधीन होता है तो अद्यतन चलाएं। एकमात्र अन्य विधि जिसकी आपने कोशिश नहीं की है वह एडीओ कमांड ऑब्जेक्ट का उपयोग करना है, और प्रत्यक्ष INSERT कथन जारी करना है। रिकॉर्डसेट ऑब्जेक्ट की 'AddNew' विधि का उपयोग करते समय, आवेषण के अंत में केवल एक 'अपडेटबैच' कमांड जारी करना सुनिश्चित करें। उस से कम, वीबीए केवल एसक्यूएल सर्वर इनपुट स्वीकार करने के रूप में तेजी से चला सकता है।

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

+0

-इंडेक्स कोई समस्या नहीं है क्योंकि मैं एक temp तालिका में लोड हो रहा हूं - लेकिन धन्यवाद, मैं इसके बारे में भूल गया था। निश्चित रूप से केवल एक कनेक्शन का उपयोग कर। एडीओ कमांड ऑब्जेक्ट के लिए, मैंने कोशिश की है लेकिन एसपी को पार करने की तुलना में यह गति में कोई अलग नहीं है। और हां, मैंने नए जोड़ने के माध्यम से लूपिंग के बाद केवल एक एडीओ अपडेट बैच जारी किया। .add नई विधि अभी तक सबसे तेज़ है, लेकिन केवल तभी जब कॉन्सट के साथ प्रयोग किया जाता है - जिसे बाद में पार्स किया जाना होगा। – cshenderson

+0

मैं थोक लॉग रिकवरी मोड में देखूंगा। – cshenderson

0

ऐसा करने का सबसे तेज़ तरीका टी-एसक्यूएल के BULK INSERT के माध्यम से है।

कुछ चेतावनियां हैं।

  • आप की संभावना एक csv पहले (आप Excel से सीधे आयात करने में सक्षम हो सकता है करने के लिए अपने डेटा को निर्यात करने की आवश्यकता होगी; Access से जा रहा में मेरा अनुभव है SQL सर्वर के .mdbs जो अंतरिम कदम की आवश्यकता csv करने के लिए)।
  • SQL सर्वर मशीन को उस csv (तक पहुंचने की आवश्यकता है जब आप BULK INSERT आदेश चलाते हैं और फ़ाइल नाम निर्दिष्ट करते हैं, याद रखें कि फ़ाइल नाम उस मशीन पर हल किया जाएगा जहां SQL सर्वर चल रहा है)।
  • आपको अपने सीएसवी से मेल खाने के लिए डिफ़ॉल्ट FIELDTERMINATOR और ROWTERMINATOR मानों को ट्विक करने की आवश्यकता हो सकती है।

शुरुआत में यह सेट अप करने के लिए मेरे लिए कुछ परीक्षण और त्रुटि आई, लेकिन प्रदर्शन की वृद्धि मैंने कोशिश की हर दूसरी तकनीक की तुलना में असाधारण थी।

+0

धन्यवाद, लेकिन बीसीपी एक विकल्प नहीं है। मैं फ्लाई पर हजारों प्रारूपों से निपटता हूं और बीसीपी ने मुझे हर बार आपदा के कारण पर्याप्त परेशानी नहीं दी है। मुझे कुछ ऐसा चाहिए जो बैच लूप के दौरान त्रुटि प्रतिक्रिया के साथ नियंत्रित कर सके; और यह अधिकांश थोक कार्यक्रमों को समाप्त करता है ... विशेष रूप से बीसीपी। – cshenderson

+0

मुझे बीसीपी == 'बल्क इन्टरेट' का एहसास नहीं हुआ। उस ने कहा, मेरे पास शुरुआती बीसीपी के साथ काम करने के समान मुद्दे थे। मैं आपकी परिस्थिति के विनिर्देशों को नहीं जानता, लेकिन मैंने कस्टम पंक्ति और फील्ड टर्मिनेटर का उपयोग करके समस्याओं को हल किया और डेटा को "मालिश" किया जब मैंने इसे सीएसवी में निर्यात किया। मैंने आपके द्वारा सूचीबद्ध अधिकांश चीज़ों की विविधताओं की कोशिश की और प्रदर्शन कभी भी थोक सम्मिलन के करीब नहीं आया। मैं मानता हूं कि थोक सम्मिलन "कमजोर" है (कम से कम कहने के लिए) और बैच लूप के दौरान त्रुटि प्रतिक्रिया असंभव के बगल में है (कुछ प्रकार के क्लेज का उपयोग किए बिना), लेकिन मुझे लगता है कि यह एक और दिखने लायक है। शुभकामनाएँ! – mwolfe02

2

निम्नलिखित कोड हजारों डेटा को केवल कुछ सेकंड (2-3 सेकंड) में स्थानांतरित कर देगा।

Dim sheet As Worksheet 
    Set sheet = ThisWorkbook.Sheets("DataSheet")   

    Dim Con As Object 
    Dim cmd As Object 
    Dim ServerName As String 
    Dim level As Long 
    Dim arr As Variant 
    Dim row As Long 
    Dim rowCount As Long 

    Set Con = CreateObject("ADODB.Connection") 
    Set cmd = CreateObject("ADODB.Command") 

    ServerName = "192.164.1.11" 

    'Creating a connection 
    Con.ConnectionString = "Provider=SQLOLEDB;" & _ 
            "Data Source=" & ServerName & ";" & _ 
            "Initial Catalog=Adventure;" & _ 
            "UID=sa; PWD=123;" 

    'Setting provider Name 
    Con.Provider = "Microsoft.JET.OLEDB.12.0" 

    'Opening connection 
    Con.Open     

    cmd.CommandType = 1    ' adCmdText 

    Dim Rst As Object 
    Set Rst = CreateObject("ADODB.Recordset") 
    Table = "EmployeeDetails" 'This should be same as the database table name. 
    With Rst 
     Set .ActiveConnection = Con 
     .Source = "SELECT * FROM " & Table 
     .CursorLocation = 3   ' adUseClient 
     .LockType = 4    ' adLockBatchOptimistic 
     .CursorType = 0    ' adOpenForwardOnly 
     .Open 

     Dim tableFields(200) As Integer 
     Dim rangeFields(200) As Integer 

     Dim exportFieldsCount As Integer 
     exportFieldsCount = 0 

     Dim col As Integer 
     Dim index As Integer 
     index = 1 

     For col = 1 To .Fields.Count 
      exportFieldsCount = exportFieldsCount + 1 
      tableFields(exportFieldsCount) = col 
      rangeFields(exportFieldsCount) = index 
      index = index + 1 
     Next 

     If exportFieldsCount = 0 Then 
      ExportRangeToSQL = 1 
      GoTo ConnectionEnd 
     End If    

     endRow = ThisWorkbook.Sheets("DataSheet").Range("A65536").End(xlUp).row 'LastRow with the data. 
     arr = ThisWorkbook.Sheets("DataSheet").Range("A1:CE" & endRow).Value 'This range selection column count should be same as database table column count. 

     rowCount = UBound(arr, 1)    

     Dim val As Variant 

     For row = 1 To rowCount 
      .AddNew 
      For col = 1 To exportFieldsCount 
       val = arr(row, rangeFields(col)) 
        .Fields(tableFields(col - 1)) = val 
      Next 
     Next 

     .UpdateBatch 
    End With 

    flag = True 

    'Closing RecordSet. 
    If Rst.State = 1 Then 
     Rst.Close 
    End If 

    'Closing Connection Object. 
    If Con.State = 1 Then 
     Con.Close 
    End If 

'Setting empty for the RecordSet & Connection Objects 
Set Rst = Nothing 
Set Con = Nothing 
End Sub 
+0

यह SQL सर्वर से Excel को डेटा लिख ​​रहा है, जैसा कि सवाल पूछ रहा है, दूसरी तरफ नहीं। – thursdaysgeek

+1

@thursdaysgeek नहीं, यह वही करता है जो सवाल पूछ रहा है। –

0

काम करता है सुंदर ठीक, हम अभी भी क्वेरी को संशोधित कर सकते गति में सुधार करने दूसरी ओर:

बजाय: Source = "SELECT * FROM " & Table

हम उपयोग कर सकते हैं: Source = "SELECT TOP 1 * FROM " & Table

यहाँ हम केवल जरूरत है कॉलम नाम तो पूरी तालिका के लिए एक क्वेरी बनाने की कोई ज़रूरत नहीं है, जो तब तक प्रक्रिया को विस्तारित कर रहा है जब तक कि नया डेटा आयात नहीं किया जाता है।

0

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

0

कुछ तरीकों की कोशिश करने के बाद, मैं अपेक्षाकृत सरल लेकिन तेज़ी से वापस आया। यह तेज़ है क्योंकि यह SQL सर्वर को सभी निष्पादन करता है, जिसमें एक कुशल निष्पादन योजना भी शामिल है।

मैं सिर्फ एक लंबी स्ट्रिंग का निर्माण करता हूं जिसमें INSERT कथन की एक स्क्रिप्ट शामिल है।

Public Sub Upload() 
     Const Tbl As String = "YourTbl" 
     Dim InsertQuery As String, xlRow As Long, xlCol As Integer 
     Dim DBconnection As New ADODB.Connection 

     DBconnection.Open "Provider=SQLOLEDB.1;Password=MyPassword" & _ 
      ";Persist Security Info=false;User ID=MyUserID" & _ 
      ";Initial Catalog=MyDB;Data Source=MyServer" 

     InsertQuery = "" 
     xlRow = 2 
     While Cells(xlRow, 1) <> "" 
      InsertQuery = InsertQuery & "INSERT INTO " & Tbl & " VALUES('" 

      For xlCol = 1 To 6 'Must match the table structure 
       InsertQuery = InsertQuery & Replace(Cells(xlRow, xlCol), "'", "''") & "', '" 'Includes mitigation for apostrophes in the data 
      Next xlCol 
      InsertQuery = InsertQuery & Format(Now(), "M/D/YYYY") & "')" & vbCrLf 'The last column is a date stamp, either way, don't forget to close that parenthesis 
      xlRow = xlRow + 1 
     Wend 

     DBconnection.Execute InsertQuery 'I'll leave any error trapping to you 
     DBconnection.Close 'But do be tidy :-) 
     Set DBconnection = Nothing 
    End Sub 
संबंधित मुद्दे