के समानांतर में एक बड़ी सीएसवी फ़ाइल निर्यात करें मेरे पास एक बड़ी सीएसवी फ़ाइल है ... 10 कॉलम, 100 मिलियन पंक्तियां, मेरी हार्ड डिस्क पर लगभग 6 जीबी आकार। मैं इस सीएसवी फ़ाइल लाइन को लाइन से पढ़ना चाहता हूं और फिर SQL थोक प्रतिलिपि का उपयोग कर डेटा को Microsoft SQL सर्वर डेटाबेस में लोड करना चाहता हूं। मैंने यहां और इंटरनेट पर भी कुछ धागे पढ़े हैं। ज्यादातर लोग सुझाव देते हैं कि समांतर में एक सीएसवी फ़ाइल पढ़ने से दक्षता के मामले में ज्यादा खरीद नहीं होती है क्योंकि कार्य/थ्रेड डिस्क एक्सेस के लिए संघर्ष करते हैं।एसक्यूएल सर्वर
जो मैं करने की कोशिश कर रहा हूं वह है, सीएसवी से लाइन द्वारा लाइन पढ़ें और आकार 100K पंक्तियों के संग्रह को अवरुद्ध करने के लिए इसे जोड़ें। और एक बार यह संग्रह SQLBuckCopy API का उपयोग कर SQL सर्वर पर डेटा लिखने के लिए एक नया कार्य/थ्रेड पूर्ण हो गया है।
मैंने कोड का यह टुकड़ा लिखा है, लेकिन रन टाइम पर एक त्रुटि मार रहा है जो कहता है "लंबित ऑपरेशन वाले ऑब्जेक्ट पर थोक प्रतिलिपि लगाने का प्रयास।" यह परिदृश्य ऐसा कुछ दिखता है जिसे आसानी से .NET 4.0 TPL का उपयोग करके हल किया जा सकता है लेकिन मैं इसे काम नहीं कर पा रहा हूं। मैं क्या गलत कर रहा हूँ पर कोई सुझाव?
public static void LoadCsvDataInParalleToSqlServer(string fileName, string connectionString, string table, DataColumn[] columns, bool truncate)
{
const int inputCollectionBufferSize = 1000000;
const int bulkInsertBufferCapacity = 100000;
const int bulkInsertConcurrency = 8;
var sqlConnection = new SqlConnection(connectionString);
sqlConnection.Open();
var sqlBulkCopy = new SqlBulkCopy(sqlConnection.ConnectionString, SqlBulkCopyOptions.TableLock)
{
EnableStreaming = true,
BatchSize = bulkInsertBufferCapacity,
DestinationTableName = table,
BulkCopyTimeout = (24 * 60 * 60),
};
BlockingCollection<DataRow> rows = new BlockingCollection<DataRow>(inputCollectionBufferSize);
DataTable dataTable = new DataTable(table);
dataTable.Columns.AddRange(columns);
Task loadTask = Task.Factory.StartNew(() =>
{
foreach (DataRow row in ReadRows(fileName, dataTable))
{
rows.Add(row);
}
rows.CompleteAdding();
});
List<Task> insertTasks = new List<Task>(bulkInsertConcurrency);
for (int i = 0; i < bulkInsertConcurrency; i++)
{
insertTasks.Add(Task.Factory.StartNew((x) =>
{
List<DataRow> bulkInsertBuffer = new List<DataRow>(bulkInsertBufferCapacity);
foreach (DataRow row in rows.GetConsumingEnumerable())
{
if (bulkInsertBuffer.Count == bulkInsertBufferCapacity)
{
SqlBulkCopy bulkCopy = x as SqlBulkCopy;
var dataRows = bulkInsertBuffer.ToArray();
bulkCopy.WriteToServer(dataRows);
Console.WriteLine("Inserted rows " + bulkInsertBuffer.Count);
bulkInsertBuffer.Clear();
}
bulkInsertBuffer.Add(row);
}
},
sqlBulkCopy));
}
loadTask.Wait();
Task.WaitAll(insertTasks.ToArray());
}
private static IEnumerable<DataRow> ReadRows(string fileName, DataTable dataTable)
{
using (var textFieldParser = new TextFieldParser(fileName))
{
textFieldParser.TextFieldType = FieldType.Delimited;
textFieldParser.Delimiters = new[] { "," };
textFieldParser.HasFieldsEnclosedInQuotes = true;
while (!textFieldParser.EndOfData)
{
string[] cols = textFieldParser.ReadFields();
DataRow row = dataTable.NewRow();
for (int i = 0; i < cols.Length; i++)
{
if (string.IsNullOrEmpty(cols[i]))
{
row[i] = DBNull.Value;
}
else
{
row[i] = cols[i];
}
}
yield return row;
}
}
}
अपने स्वयं के टूल लिखने में समय बिताने के बजाय, एक ईटीएल उपकरण का उपयोग क्यों न करें जो पहले से ही SQL सर्वर एकीकरण सेवाओं जैसे ऐसा करता है। –
क्या आपने इस कोड के अनुक्रमिक संस्करण की कोशिश की है और क्या आपने साबित किया है कि बहु-थ्रेडिंग की जटिलता प्रदर्शन लाभ के लायक है? – Cory
थोक आवेषण को अनुकूलित करने के लिए कई ऑनलाइन मार्गदर्शिकाएं हैं, यानी http://technet.microsoft.com/en-us/library/ms190421(v=sql.105).aspx। ऐसा लगता है कि आप ऐसी समस्या को हल करने की कोशिश कर रहे हैं जिसे आपने साबित नहीं किया है। मेरा सुझाव है कि आप पहले 'बीसीपी.एक्सईई' का उपयोग करके बेसलाइन प्राप्त करें और फिर उस समय कोशिश करें और सुधार करें। –