我正在使用控制台应用程序将数据插入MS SQL Server 2005数据库。我有一个要插入的对象列表。这里我以Employee类为例:
List<Employee> employees;
我能做的就是像这样插入一个物体:
foreach (Employee item in employees)
{
string sql = @"INSERT INTO Mytable (id, name, salary)
values ('@id', '@name', '@salary')";
// replace @par with values
cmd.CommandText = sql; // cmd is IDbCommand
cmd.ExecuteNonQuery();
}
或者我可以像这样构建一个balk插入查询:
string sql = @"INSERT INTO MyTable (id, name, salary) ";
int count = employees.Count;
int index = 0;
foreach (Employee item in employees)
{
sql = sql + string.format(
"SELECT {0}, '{1}', {2} ",
item.ID, item.Name, item.Salary);
if ( index != (count-1) )
sql = sql + " UNION ALL ";
index++
}
cmd.CommandType = sql;
cmd.ExecuteNonQuery();
我想后一种情况是一次性插入数据行。但是,如果我有 几个k的数据,SQL查询字符串是否有任何限制?
我不确定在性能方面,一行插入多行是否优于一行插入一行数据?
有什么建议以更好的方式做到这一点吗?
答案 0 :(得分:14)
实际上,你写它的方式,你的第一个选择会更快。
您的第二个示例中存在问题。你正在做sql = + sql +等。这将导致为循环的每次迭代创建一个新的字符串对象。 (查看StringBuilder类)。从技术上讲,您将在第一个实例中创建一个新的字符串对象,但区别在于它不必复制上一个字符串选项中的所有信息。
你设置它的方式,当你最终发送它时,SQL Server将不得不潜在地评估一个大量的查询,这肯定需要一些时间来弄清楚它应该做什么。我应该说,这取决于你需要做多大的插入。如果n很小,你可能会好起来,但随着它的增长你的问题只会变得更糟。
由于SQL Server处理批处理事务的方式,批量插入比单个插入更快。如果要从C#插入数据,则应采用第一种方法并将每500次插入包装说明并提交,然后执行下一次500,依此类推。这样做的另一个好处是,如果批次失败,您可以捕获这些并找出出错的地方并重新插入。还有其他方法可以做到,但这绝对是对所提供的两个例子的改进。
var iCounter = 0;
foreach (Employee item in employees)
{
if (iCounter == 0)
{
cmd.BeginTransaction;
}
string sql = @"INSERT INTO Mytable (id, name, salary)
values ('@id', '@name', '@salary')";
// replace @par with values
cmd.CommandText = sql; // cmd is IDbCommand
cmd.ExecuteNonQuery();
iCounter ++;
if(iCounter >= 500)
{
cmd.CommitTransaction;
iCounter = 0;
}
}
if(iCounter > 0)
cmd.CommitTransaction;
答案 1 :(得分:3)
在MS SQL Server 2008中,您可以创建包含表格的.Net table-UDT
CREATE TYPE MyUdt AS TABLE (Id int, Name nvarchar(50), salary int)
然后,您可以在存储过程中使用此UDT,并将с#-code用于批量插入。 SP:
CREATE PROCEDURE uspInsert
(@MyTvp AS MyTable READONLY)
AS
INSERT INTO [MyTable]
SELECT * FROM @MyTvp
C#(想象一下你需要插入的记录已包含在DataSet ds的表“MyTable”中):
using(conn)
{
SqlCommand cmd = new SqlCommand("uspInsert", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter myParam = cmd.Parameters.AddWithValue
("@MyTvp", ds.Tables["MyTable"]);
myParam.SqlDbType = SqlDbType.Structured;
myParam.TypeName = "dbo.MyUdt";
// Execute the stored procedure
cmd.ExecuteNonQuery();
}
所以,这就是解决方案。
最后,我想阻止你使用像你这样的代码(构建字符串然后执行这个字符串),因为这种执行方式可以用于SQL注入。
答案 2 :(得分:0)
看看this thread, 我在那里回答了有关表值的参数。
答案 3 :(得分:0)
Bulk-copy通常比自行插入更快。
如果您仍希望以建议的方式执行此操作,则应该可以轻松更改发送到服务器的查询的大小。这样,您可以在以后优化生产环境中的速度。查询时间可能很长,具体取决于查询大小。
答案 4 :(得分:0)
SQL Server查询的批处理大小列为65,536 *网络包大小。网络数据包大小默认为4kbs,但可以更改。查看SQL 2008的Maximum capacity articl e以获取范围。 SQL 2005似乎也有相同的限制。