C# SQL插入命令

6
有人能告诉我以下两种插入记录的方法哪一个具有更好的性能吗? 情况1
SqlCommand cmd = new SqlCommand();

for (int i = 0; i < 10000; i++)
{
  cmd = new SqlCommand("insert into test(id, name) value('" + i + "', '" + i + "')");
  cmd.ExecuteNonQuery();
}

案例二

string sql = null;

for (int i = 0; i < 10000; i++)
{
  sql += "insert into test(id, name) value('" + i + "', '" + i + "')";
}

SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();

3
你是否进行过简单的时间测试?将每个执行10,000次,并观察哪一个运行得更快。 - abelenky
相同,但首选第一种情况。相同是因为您将使用连接池。 - SQLMason
16
首先:停止将你的SQL代码串联在一起!这会邀请黑客使用SQL注入攻击你!改用参数化查询来替代! - marc_s
4
@DanAndrews:真的?!?!?你认为创建10,000个SqlCommand实例并逐一执行它们的速度与创建一个单独的实例并仅执行一次相同吗? - marc_s
你是对的,这样会更快。 - SQLMason
5个回答

63

首先:停止将您的SQL代码串联在一起!! 这是邀请到处都有SQL注入攻击者攻击您的行为!使用参数化查询代替!

我会使用这个解决方案:创建一个带有参数化查询的单个SqlCommand,并执行它:

string stmt = "INSERT INTO dbo.Test(id, name) VALUES(@ID, @Name)";

SqlCommand cmd = new SqlCommand(smt, _connection);
cmd.Parameters.Add("@ID", SqlDbType.Int);
cmd.Parameters.Add("@Name", SqlDbType.VarChar, 100);

for (int i = 0; i < 10000; i++)
{
    cmd.Parameters["@ID"].Value = i;
    cmd.Parameters["@Name"].Value = i.ToString();

    cmd.ExecuteNonQuery();
}

或者使用 SqlBulkCopy,尤其是在插入超过10,000行的情况下。


1
虽然我通常同意直接传递未经过净化的参数到串联SQL是不好的,但在这个代码的上下文中它实际上是无害的。没有要关注的用户输入值 - 看起来只是一个快速的一次性操作。 - hajikelist
新的推荐方法是使用AddWithValue - Si8
我一直使用Add,但最近因为它而改用AddWithValue。很高兴我看到了你的建议和注释。 - Si8
@Si8:吓人啊!那是官方的微软文档...但是,确实有一种过载已经被弃用了 - 但你绝对不应该使用AddWithValue来替代它!谢谢。 - marc_s
1
我想象VS和C#都是微软的产品,他们不会推荐不准确的东西,但是我使用过SharePoint,情况绝对不是这样!即使VS给出警告,我仍然会坚持使用Add() - Si8
显示剩余5条评论

6
第二种方法比第一种方法看起来更快,因为您可以一次性发送INSERT命令。在第一种方法中,每个ExecuteNonQuery都需要与SQL服务器进行一次往返通信。
但是您应该尝试使用批量插入命令:BULK INSERT (Transact-SQL),我猜您将获得比您提供的任何选项都要好的性能。
[]'s

1
虽然这可能是一个好主意,但它如何回答“选项1和选项2哪个更快?”的问题呢?你说:“改为选择选项3。” - Ken White
2
@KenWhite 我认为这个答案非常合适。它没有直接回答问题,因为OP使用了一种低效的方法。我有一个预感,OP并不是在寻找哪种方式使用更少的CPU周期(如果他们确切地想知道这一点,他们可以很容易地自行测试)。相反,我相信OP正在尝试理解哪种方式更有效,而Fabio提供的解决方案比OP的任何一种都要好。 - Kiley Naro
1
它并不是。正如你所说,这是第三个选项。有时候我们得不到我们想要的确切答案,但我们得到了让我们从不同角度看待事物的东西。[] - Fabio
1
我非常讨厌看到那些没有回答被问出的非常具体问题的答案被投票赞同。 - SQLMason
@KenWhite,值得一提的是,虽然marc_s提供的答案根本不能“回答特定问题”(它绝对是一个“执行选项3而不是”的答案),但这无疑是最好的答案。出于好奇,您对他的答案的感觉是否和对Fabio的回答感觉相同? - Kiley Naro
显示剩余2条评论

1

需要注意的是,无论哪种情况,原样都不会起作用。

情况#1需要指定连接。

情况#2要求您在语句末尾加上分号以运行多个命令,如下所示:

string sql = null;

for (int i = 0; i < 10000; i++)
{
  sql += "insert into test(id, name) value('" + i + "', '" + i + "');";
}

SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();

最好的方式是让您自己在几千行上进行测试。我猜测情况#2的性能会更好,因为它不仅需要设置一个SqlCommand对象,而且只需要一次访问数据库。

1

我认为第二个选项不会起作用。

然而,在SQL Server 2008中有一种语法可以在单个INSERT语句中插入多行数据,我认为这比你提出的两个选项都要快:

INSERT INTO test (id, name)
VALUES
('1', 'foo'),
('2', 'bar'),
('3', 'baz')
 -- etc...

然而,如果您真的想要高性能,请考虑使用SqlBulkCopy类。


0
第二个可能更快,因为你最终只需要一次往返。但两者都同样糟糕,因为你没有使用参数化查询

3
@Kiley: 我不明白你在这里发帖的意义,除了挑起争端之外。 - Sergey Kalinichenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接