我开发了一个程序,它在一个循环中计算并插入大约4800行到SQL Server 2008.但是在插入200多行之后,它每次都被卡住并且不会插入其余的行。
现在我在循环中用insert命令编写一个文本文件,而不是插入到DB中。如果我尝试从文本日志中复制整个4800插入命令并将其粘贴到SQL Server的查询编辑器中,那么它会在1分钟内插入所有内容。我想就如何解决这个问题提出建议?我将不胜感激任何建议或帮助。
以下是我现在正在尝试的代码示例:
strSQL = "Insert into performance Values (@Rptdate,@CP_Name, @Shortcode, @Keyword, @MO_Count, @MO_Revenue,";
strSQL = strSQL + "@PMT_Sent_Count, @MT_Revenue, @ZMT_Sent_Count, @Infra_Revenue, @Total_MT, @UM_rev_Share, @CP_Rev_Share, ";
strSQL = strSQL + "@MCP_Rev_Share, @UM_Total_Revenue, @CP_Revenue)";
try
{
db.openconn("MOMT_Report", "Report");
cmd = new SqlCommand(strSQL, db.cn);
cmd.Parameters.AddWithValue("@Rptdate", Rptdate);
cmd.Parameters.AddWithValue("@Name", Name);
cmd.Parameters.AddWithValue("@Shortcode", Shortcode);
cmd.Parameters.AddWithValue("@Keyword", Keyword);
cmd.Parameters.AddWithValue("@MO_Count", MO_Count);
cmd.Parameters.AddWithValue("@MO_Revenue", MO_Revenue);
cmd.Parameters.AddWithValue("@PMT_Sent_Count", PMT_Sent_Count);
cmd.Parameters.AddWithValue("@MT_Revenue", MT_Revenue);
cmd.Parameters.AddWithValue("@ZMT_Sent_Count", ZMT_Sent_Count);
cmd.Parameters.AddWithValue("@Infra_Revenue", Infra_Revenue);
cmd.Parameters.AddWithValue("@Total_MT", Total_MT);
cmd.Parameters.AddWithValue("@rev_Share", rev_Share);
cmd.Parameters.AddWithValue("@Rev_Share", Rev_Share);
cmd.Parameters.AddWithValue("@MCP_Rev_Share", MCP_Rev_Share);
cmd.Parameters.AddWithValue("@Total_Revenue", Total_Revenue);
cmd.Parameters.AddWithValue("@Revenue", Revenue);
cmd.CommandTimeout = 0;
cmd.ExecuteNonQuery();
}
答案 0 :(得分:1)
使用批量插入。 这里很好地描述了: http://blogs.msdn.com/b/nikhilsi/archive/2008/06/11/bulk-insert-into-sql-from-c-app.aspx
答案 1 :(得分:1)
我认为您需要先在下面的链接中设置超时选项:
http://msdn.microsoft.com/en-us/library/ms189470.aspx
然后尝试更改max allowed packet:
http://msdn.microsoft.com/en-us/library/ms177437.aspx
希望它能运作
答案 2 :(得分:1)
在粘贴到问题中的try块之后的某个地方是否有db.closeconn();
?如果没有,那么这是一个很大的问题(即保持打开连接而不关闭它们,这可以解释为什么它在打开200多个之后冻结)。如果有一个关闭连接方法被调用那么很好,但仍然,每个INSERT打开和关闭连接是不必要的,更不用说非常低效了。
至少你可以:
SqlParameter
和SqlCommand
一次ExecuteNonQuery();
AddWithValue()
)示例:
// this should be in a try block
strSQL = "INSERT...";
db.openconn("MOMT_Report", "Report");
cmd = new SqlCommand(strSQL, db.cn);
SqlParameter _Rptdate = new SqlParameter("@Rptdate", DbType.Int);
cmd.Parameters.Add(_Rptdate);
...{repeat for remaining params}...
// optional begin transaction
for / while loop
{
_Rptdate.Value = Rptdate;
// set other param values
cmd.ExecuteNonQuery();
}
// if optional transaction was started, do commit
db.closeconn(); // this should be in a finally block
但是,插入此数据的最快和最干净的方法是使用SQL Server 2008中引入的表值参数(TVP)。您需要创建用户定义的表类型(一次)来定义结构,然后您可以在当前具有的临时插入中使用它,或者传递给存储过程。但是这样您就不需要导出到导入文件了。不需要额外的步骤。
我没有复制/粘贴大型代码块,而是注意到下面的三个链接,我已经发布了代码来执行此操作。前两个链接是完成此代码的完整代码(SQL和C#)。每个主题都略有不同(表明使用TVP的灵活性)。第三个是另一个变体,但不是完整的代码,因为它只显示前两个中的一个的差异,以适应特定的情况。但在所有3种情况下,数据从应用程序流式传输到SQL Server 。没有创建任何其他集合或外部文件;您使用当前拥有的内容,只需要一次复制单行的值即可发送。在SQL Server端,它都是作为填充的表变量而来的。这比获取内存中的数据,将其转换为文件(占用时间和磁盘空间)或XML(占用CPU和内存)或DataTable(适用于SqlBulkCopy
;获取cpu和内存)要高效得多或其他什么,只依赖于文件系统等外部因素(文件需要清理,对吗?)或者需要解析XML。
答案 3 :(得分:1)
执行一个sqlcommand比执行4800 sqlcommands要好得多 有几种方法, 对于批量插入,您需要从数据库服务器访问 .txt 文件(将文件传输到数据库服务器或者可以通过网络访问该文件) 之后使用:
BULK INSERT Your_table
FROM 'full_file_name'
WITH
(
FIELDTERMINATOR =' terminator character',
ROWTERMINATOR = ':\n'
);
另一种方式:您可以在C#代码中构建一个新文本,该代码具有每行的插入命令并执行整个文本一次(最好将其放入事务中)
答案 4 :(得分:1)
我认为如果你需要使用XML批量插入,那么你也可以使用这种方法..
首先创建一个这样的商店程序..
CREATE PROCEDURE SP_INSERT_BULK
@DataXML XML
AS
BEGIN
INSERT INTO performance
SELECT
d.value('@Rptdate','varchar') AS Rptdate
,d.value('@Name','varchar') AS Name
,d.value('@Shortcode','varchar') AS Shortcode
,d.value('@Keyword','varchar') AS Keyword
,d.value('@MO_Count','varchar') AS MO_Count
,d.value('@MO_Revenue','varchar') AS MO_Revenue
,d.value('@PMT_Sent_Count','varchar') AS PMT_Sent_Count
,d.value('@MT_Revenue','varchar') AS MT_Revenue
,d.value('@ZMT_Sent_Count','varchar') AS ZMT_Sent_Count
,d.value('@Infra_Revenue','varchar') AS Infra_Revenue
,d.value('@Total_MT','varchar') AS Total_MT
,d.value('@rev_Share','varchar') AS rev_Share
,d.value('@Rev_Share','varchar') AS Rev_Share
,d.value('@MCP_Rev_Share','varchar') AS MCP_Rev_Share
,d.value('@Total_Revenue','varchar') AS Total_Revenue
,d.value('@Revenue','varchar') AS Revenue
FROM @DataXML.nodes('Reports/Report') n(d)
END
以上商店程序仅供演示,您可以使用自己的逻辑进行修改
现在下一步是创建数据XML以作为参数
传递到您的商店过程 //prepare your data xml here
//you can use any of your logic to prepare dataxml
string xmlstring = @"<?xml version='1.0' encoding='utf-8'?><Reports>";
for (int i = 0; i < recordcout; i++)
{
xmlstring += string.Format(@"<Report Rptdate='{0}'
Name='{1}'
Shortcode='{2}'
Keyword='{3}'
MO_Count='{4}'
MO_Revenue ='{5}'
PMT_Sent_Count='{6}'
MT_Revenue='{7}'
ZMT_Sent_Count ='{8}'
Infra_Revenue='{9}'
Total_MT='{10}'
rev_Share='{11}'
Rev_Share='{12}'
MCP_Rev_Share='{13}'
Total_Revenue='{14}'
Revenue='{15}' />");
}
xmlstring += "</Reports>";
现在,下一步是将此XML字符串传递给您的商店过程
using (SqlConnection dbConnection = new SqlConnection("CONNECTIONSTRING"))
//Create database connection
{
// Database command with stored - procedure
using (SqlCommand dbCommand =
new SqlCommand("SP_INSERT_BULK", dbConnection))
{
// we are going to use store procedure
dbCommand.CommandType = CommandType.StoredProcedure;
// Add input parameter and set its properties.
SqlParameter parameter = new SqlParameter();
// Store procedure parameter name
parameter.ParameterName = "@DataXML";
// Parameter type as XML
parameter.DbType = DbType.Xml;
parameter.Direction = ParameterDirection.Input; // Input Parameter
parameter.Value = xmlstring; // XML string as parameter value
// Add the parameter in Parameters collection.
dbCommand.Parameters.Add(parameter);
dbConnection.Open();
int intRetValue = dbCommand.ExecuteNonQuery();
}
}
答案 5 :(得分:1)
您应该在一次交易中完成所有这些工作。
Open DB connection.
Create command.
Begin transaction.
Start loop.
Clear parameters if added
Set parameters and execute it.
End loop.
Commit transaction.
Close DB connection.