Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在尽可能短的时间内插入1000万条记录?_C#_Sql Server_Import_Bulkinsert_Table Valued Parameters - Fatal编程技术网

C# 如何在尽可能短的时间内插入1000万条记录?

C# 如何在尽可能短的时间内插入1000万条记录?,c#,sql-server,import,bulkinsert,table-valued-parameters,C#,Sql Server,Import,Bulkinsert,Table Valued Parameters,我有一个文件(有1000万条记录),如下所示: line1 第2行 第3行 第4行 ....... ...... 1000万行 所以基本上我想在数据库中插入1000万条记录。 因此,我读取了该文件并将其上载到SQL Server C#代码 System.IO.StreamReader文件= 新System.IO.StreamReader(@“c:\test.txt”); 而((line=file.ReadLine())!=null) { //插入代码在这里 //DAL.ExecuteSql(“

我有一个文件(有1000万条记录),如下所示:

line1
第2行
第3行
第4行
.......
......
1000万行
所以基本上我想在数据库中插入1000万条记录。 因此,我读取了该文件并将其上载到SQL Server

C#代码

System.IO.StreamReader文件=
新System.IO.StreamReader(@“c:\test.txt”);
而((line=file.ReadLine())!=null)
{
//插入代码在这里
//DAL.ExecuteSql(“插入表1中的值(“+line+”));
}
file.Close();
但插入需要很长时间。 如何使用C#在尽可能短的时间内插入1000万条记录

更新1:
批量插入:

批量插入DBNAME.dbo.DATAs
来自“F:\dt10000000\dt10000000.txt”
具有
(
行终止符='\n'
);
我的桌子如下:

数据
(
数据字段VARCHAR(最大值)
)
但我得到了以下错误:

Msg 4866,第16级,状态1,第1行
批量加载失败。数据文件中第1行第1列的列太长。验证是否正确指定了字段终止符和行终止符

味精7399,第16级,状态1,第1行
链接服务器(null)的OLE DB提供程序“大容量”报告了错误。提供程序没有提供有关错误的任何信息

信息7330,16级,状态2,第1行
无法从链接服务器(null)的OLE DB提供程序“大容量”中获取行

以下代码有效:

批量插入DBNAME.dbo.DATAs
来自“F:\dt10000000\dt10000000.txt”
具有
(
字段终止符='\t',
行终止符='\n'
);

最好的方法是将第一种解决方案和第二种解决方案混合使用, 创建
DataTable
并在循环中向其添加行,然后使用
BulkCopy
上载 在一个连接中连接到DB

另外需要注意的是,大容量复制是一项非常敏感的操作,几乎 每个错误都会使副本无效,例如,如果您在dataTable中声明列名为“text”,在DB中声明列名为“text”,则会引发异常,祝您好运。

请不要创建要通过BulkCopy加载的
dataTable
。对于较小的数据集来说,这是一个不错的解决方案,但是在调用数据库之前,绝对没有理由将所有1000万行加载到内存中

您的最佳选择(在
BCP
/
批量插入
/
OPENROWSET(批量…
)之外)是通过表值参数(TVP)将文件中的内容流式传输到数据库中。通过使用TVP,您可以打开文件,读取一行并发送一行,直到完成,然后关闭文件。此方法的内存占用仅为一行。我写了一篇文章,其中有一个例子就是这种情况

结构的简单概述如下。我假设导入表和字段名与上述问题中显示的相同

所需的数据库对象:

--首先:您需要一个用户定义的表类型
创建类型ImportStructure作为表(字段VARCHAR(MAX));
去
--第二:将UDTT用作导入过程的输入参数。
--因此,“表值参数”(TVP)
创建过程dbo.ImportData(
@可导入dbo.ImportStructure只读
)
作为
不计数;
--也许先把桌子清理干净?
截断表dbo.DATAs;
插入dbo.DATAs(数据字段)
选择字段
来自@importable;
去
下面是使用上述SQL对象的C#应用程序代码。请注意,在这种方法中,不是填充对象(例如DataTable)然后执行存储过程,而是执行存储过程来启动文件内容的读取。存储过程的输入参数不是变量;它是方法的返回值,
GetFileContents
。当
SqlCommand
调用
ExecuteNonQuery
,打开文件,读取一行,并通过
IEnumerable
yield return
构造将行发送到SQL Server,然后关闭文件时,将调用该方法。存储过程只看到一个表变量@importable,一旦数据开始出现,就可以访问它(注意:数据在tempdb中会持续很短时间,即使不是完整的内容)

使用系统集合;
使用系统数据;
使用System.Data.SqlClient;
使用System.IO;
使用Microsoft.SqlServer.Server;
私有静态IEnumerable GetFileContents()
{
SqlMetaData[]\u TvpSchema=新的SqlMetaData[]{
新的SqlMetaData(“字段”,SqlDbType.VarChar,SqlMetaData.Max)
};
SqlDataRecord _DataRecord=新的SqlDataRecord(_TvpSchema);
StreamReader _FileReader=null;
尝试
{
_FileReader=新的StreamReader(“{filePath}”);
//读一行,发一行
而(!\u FileReader.EndOfStream)
{
//您不需要将“\u DataRecord=new SqlDataRecord”作为
//SQL Server在调用“yield return”时已收到该行。
//与BCP和大容量插入不同,您可以在此处选择创建字符串
//将ReadLine()调用到字符串中,对
//字符串,然后将该字符串传递到SetString()中,如果无效,则放弃该字符串。
_DataRecord.SetString(0,_FileReader.ReadLine());
收益率返回数据记录;
}
}
最后
{
_FileReader.Close();
}
}
上面的
GetFileContents
方法用作存储过程的输入参数值,如下所示:

公共静态无效测试()
{
SqlConnection _Connection=newsqlconnection(“{Connection string}”);
SqlCommand _Command=newsqlcommand(“ImportData”,_连接);
_Command.CommandType=CommandType.storedProcess;
SqlParameter _TVParam=新的SqlParameter();
_TVParam.ParameterName=“@importable”;
_TVParam.TypeName=“dbo.ImportStructure”;
_TVParam.SqlDbType=SqlDbType.St
 CREATE TABLE TestData(ID INT IDENTITY (1,1), CreatedDate DATETIME)
 GO

 INSERT INTO TestData(CreatedDate) SELECT GetDate()
 GO 10000000