在C#中使用SqlCommand准备的优点和缺点?

时间:2010-03-15 19:23:16

标签: c# sql-server performance

当我读书学习C#(可能是一些旧的Visual Studio 2005书籍)时,我遇到过建议,每次执行SQL调用时都要使用SqlCommand.Prepare(无论是{a {{1}我在SQL SERVER 2005/2008上使用/ SELECTUPDATE并将参数传递给它。 但它真的如此

  1. 每次都应该这样做吗?或者有时候?

  2. 它是一个参数传递还是五个或二十个是否重要?

  3. 如果有的话应该提供什么?它是否会引人注目(我一直在这里使用INSERT并在那里跳过它,从来没有任何问题或明显的差异)。

  4. 为了问题,这是我使用的常用代码,但这更像是一个普遍的问题。

    SqlCommand.Prepare

    补充说明:

    如果我像下面的代码一样移动public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) { const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni, @varStopaOdniesienia) AS 'Benchmark'"; using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) { using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) { sqlQuery.Prepare(); sqlQuery.Parameters.AddWithValue("@varPortfelID", varPortfelID); sqlQuery.Parameters.AddWithValue("@varStopaOdniesienia", varStopaOdniesienia); sqlQuery.Parameters.AddWithValue("@data", data); sqlQuery.Parameters.AddWithValue("@varBenchmarkPoprzedni", varBenchmarkPoprzedni); using (var sqlQueryResult = sqlQuery.ExecuteReader()) if (sqlQueryResult != null) { while (sqlQueryResult.Read()) { } } } } ,则抛出必须明确声明大小的异常,这基本上会让我认为首先使用sqlQuery.Prepare()会使它无用吗?有人可以使用我的示例显示正确的用法吗?

    sqlQuery.Prepare()

    我该怎么做?通过在参数旁边添加.size并执行varPortfel.Lenght(如果它是字符串等)?

4 个答案:

答案 0 :(得分:12)

来自MSDN文档:

  

“在致电Prepare之前,请指定   中的每个参数的数据类型   声明准备。对于每一个   具有可变长度的参数   数据类型,您必须设置大小   属性到所需的最大尺寸。   如果这些准备,则准备返回错误   条件不符合。

     

如果你之后调用了Execute方法   调用Prepare,任何参数值   这个值大于值   由Size属性指定的是   自动截断到   原始指定的大小   参数,没有截断错误   归还。

     

输出参数(无论是否准备好)   not)必须有用户指定的数据   类型。如果指定可变长度   数据类型,您还必须指定   最大尺寸。“

     

此外,“如果是CommandType   property设置为TableDirect,   准备什么都不做。如果是CommandType   设置为StoredProcedure,调用   准备应该成功,......“

这通常用于确保最终用户不使用SQL注入技术来添加或删除数据库中不需要的信息。

我调查了一下,查看了这篇文章http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.prepare.aspx。您的问题是您需要在运行.Prepare()之前定义参数,然后在运行.Prepare()之后设置参数。现在你正在做两件事。我会尝试这样的事情(注意我没有测试它,所以我的语法可能有点偏。)

public static decimal pobierzBenchmarkKolejny(string varPortfelID, DateTime data, decimal varBenchmarkPoprzedni, decimal varStopaOdniesienia) {
    const string preparedCommand = @"SELECT [dbo].[ufn_BenchmarkKolejny](@varPortfelID, @data, @varBenchmarkPoprzedni,  @varStopaOdniesienia) AS 'Benchmark'";
    using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) //if (varConnection != null) {
    using (var sqlQuery = new SqlCommand(preparedCommand, varConnection)) {

        sqlQuery.Parameters.Add("@varPortfelID");
        sqlQuery.Parameters.Add("@varStopaOdniesienia");
        sqlQuery.Parameters.Add("@data");
        sqlQuery.Parameters.Add("@varBenchmarkPoprzedni");

        sqlQuery.Prepare();
        sqlQuery.ExecuteNonQuery();//This might need to be ExecuteReader()

        sqlQuery.Parameters[0].Value = varPortfelID;
        sqlQuery.Parameters[1].Value = varStopaOdniesienia;
        sqlQuery.Parameters[2].Value = data;
        sqlQuery.Parameters[3].Value = varBenchmarkPoprzedni;

        using (var sqlQueryResult = sqlQuery.ExecuteReader())
            if (sqlQueryResult != null) {
                while (sqlQueryResult.Read()) {

                }
            }
    }
}

答案 1 :(得分:6)

另一个好处是,通过这样做,SQL查询计划被编译,缓存和重用。如果对查询的调用量很小,这不是什么大问题,但如果你有很多,那么这样做确实有一些显着的性能优势。

答案 2 :(得分:4)

根据我自己的经验:性能提升非常重要。前段时间我在一个项目上工作,我们使用自己的对象关系映射。我们利用庞大的数据库作为复杂对象模型的持久存储 - 具有按需对象加载和弱引用对象生命周期。

使用准备好的命令对于该应用程序的成功至关重要,因为它单独使系统实际可用。

换句话说:如果执行许多SQL命令 - 它们完全相同或仅在参数值上有所不同 - ,您将看到巨大的性能提升。

我没有确切的数字或链接,但我可以证明自己的经验。

答案 3 :(得分:-1)

根据IDbCommand.Prepare Method documentation

  

服务器会根据需要自动缓存重用计划;   因此,无需直接在您的方法中调用此方法   客户申请。

我还发现了这个Databases Administrators answer,其中提供了有关prepare方法的大量详细信息以及为什么我没有取得任何重大改进。

关于SQL注入,您将受到保护,因为您使用了参数化的sqlCommand ...而不是因为您调用了prepare方法。