您推荐将.csv文件导入Microsoft SQL Server 2008 R2的方法是什么?
我想要一些快速的东西,因为我有一个包含很多.csv文件的目录(500个.csv文件分布在500个以上)。
我在Win 7 x64上使用SQL Server 2008 R2。
更新:解决方案
这是我如何解决问题的结局:
- 我放弃了尝试使用LINQ to Entities来完成这项工作。它有效 - 但它不支持批量插入,所以它大约慢20倍。也许LINQ to Entities的下一个版本将支持这一点。
- 在这个线程上给出了建议,使用了批量插入。
- 我创建了一个使用批量插入的T-SQL存储过程。数据进入临时表,进行规范化,然后复制到目标表中。
- 我使用LINQ to Entities框架将存储过程映射到C#(www.learnvisualstudio.net上有一个显示如何执行此操作的视频)。
- 我编写了所有代码来循环访问C#中的文件等。
- 这种方法消除了最大的瓶颈,即从驱动器读取大量数据并将其插入数据库。
这种方法读取.csv文件的速度非常快? Microsoft SQL Server可以使用自己的高度优化的例程直接从硬盘驱动器将文件直接导入数据库。大多数其他基于C#的解决方案需要更多代码,而有些(如LINQ to Entities)最终必须通过C#-to-SQL-server链接将数据缓慢地传输到数据库中。
是的,我知道拥有100%纯C#代码来完成这项工作会更好,但最终:
- (a)对于这个特殊问题,使用T-SQL需要 许多 与C#相比,代码更少,约为1/10,特别是对于从登台表中反规范化数据的逻辑。这更简单,更易于维护。
- (b)使用T-SQL意味着您可以利用本机批量插入过程,从20分钟等待到30秒暂停加速。
如果您必须对除插入文件之外的文件中的数据执行任何操作,那么我建议使用SSIS。它不仅可以插入和/或更新,还可以为您清理数据。
第一种官方支持的导入大型文本文件的方法是使用命令行工具“bcp”(批量复制实用程序),对大量二进制数据非常有用。
请查看此链接: http://msdn.microsoft.com/en-us/library/ms162802.aspx
但是,在SQL Server 2008中,我假设BULK INSERT命令是您的首选,因为它首先成为标准命令集的一部分。如果由于任何原因你必须保持垂直兼容性,我会坚持使用bcp实用程序,也可用于SQL Server 2000。
HTH :)
编辑后来:谷歌搜索我回忆说,SQL Server 2000也有BULK INSERT命令...但是,显然有一些原因我坚持使用bcp.exe,我不记得为什么......或许有一些限制,我想。
我应该推荐这个:
using System;
using System.Data;
using Microsoft.VisualBasic.FileIO;
namespace ReadDataFromCSVFile
{
static class Program
{
static void Main()
{
string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv";
DataTable csvData = GetDataTabletFromCSVFile(csv_file_path);
Console.WriteLine("Rows count:" + csvData.Rows.Count);
Console.ReadLine();
}
private static DataTable GetDataTabletFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using(TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
}
return csvData;
}
}
}
//Copy the DataTable to SQL Server using SqlBulkCopy
function static void InsertDataIntoSQLServerUsingSQLBulkCopy(DataTable csvData)
{
using(SqlConnection dbConnection = new SqlConnection("Data Source=ProductHost;Initial Catalog=yourDB;Integrated Security=SSPI;"))
{
dbConnection.Open();
using (SqlBulkCopy s = new SqlBulkCopy(dbConnection))
{
s.DestinationTableName = "Your table name";
foreach (var column in csvFileData.Columns)
s.ColumnMappings.Add(column.ToString(), column.ToString());
s.WriteToServer(csvFileData);
}
}
}
如果所有CSV的结构都相同,我建议您使用Integration Services(SSIS)在它们之间循环并将它们全部插入到同一个表中。
我明白这不是你的问题。但是,如果您遇到使用直插入的情况,请使用tablock并插入多行。取决于行大小,但我通常会在600-800行。如果它是一个空表的加载,那么有时删除索引并在加载后创建它们会更快。如果可以在聚集索引加载之前对其进行排序。如果可以,请使用IGNORE_CONSTRAINTS和IGNORE_TRIGGERS。如果可以,将数据库置于单用户模式。
使用AdventureWorks2008R2;
走
使用(tablock)插入Production.UnitMeasure
VALUES(N'FT2',N'Square Feet','20080923'),(N'Y',N'Yards','20080923'),(N'Y3',N'Cubic Yards','20080923') ;
走