改进.NET / MSSQL选择&更新性能

时间:2010-12-09 23:24:04

标签: c# .net sql-server performance

我想提高.NET& amp;的非常简单的选择和更新查询的性能。 MSSQL 2k8。 我的查询总是选择或更新单行。数据库表在我查询的列上有索引。 我的测试.NET代码如下所示:

      public static MyData GetMyData(int accountID, string symbol)
    {
            using (var cnn = new SqlConnection(connectionString))
            {
                cnn.Open();

                var cmd = new SqlCommand("MyData_Get", cnn);
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(CreateInputParam("@AccountID", SqlDbType.Int, accountID));
                cmd.Parameters.Add(CreateInputParam("@Symbol", SqlDbType.VarChar, symbol));

                SqlDataReader reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    var MyData = new MyData();
                    MyData.ID = (int)reader["ID"];
                    MyData.A = (int)reader["A"];
                    MyData.B = reader["B"].ToString();
                    MyData.C = (int)reader["C"];
                    MyData.D = Convert.ToDouble(reader["D"]);
                    MyData.E = Convert.ToDouble(reader["E"]);
                    MyData.F = Convert.ToDouble(reader["F"]);

                    return MyData;
                }
            }
    }

并且相应的存储过程如下所示:

     PROCEDURE [dbo].[MyData_Get] 
 @AccountID int,
 @Symbol  varchar(25)
AS
BEGIN
 SET NOCOUNT ON;
  SELECT p.ID, p.A, p.B, p.C, p.D, p.E, p.F FROM [MyData] AS p WHERE p.AccountID = @AccountID AND p.Symbol = @Symbol
END

我看到的是如果我在一个循环中运行GetMyData,查询MyData对象,我不会超过约310次/秒的事务。我希望能够在每秒1000次交易中取得好成绩。

在SQL Server方面,不太确定我可以为这样一个简单的查询改进。 ANTS分析器告诉我,在.NET端,正如预期的那样,瓶颈是cnn.Open和cnn.ExecuteReader,但是我不知道如何能够显着改进我的.NET代码?

我已经看过基准测试,但人们似乎很容易达到每秒数万次交易。

非常感谢任何有关如何显着提高此方案性能的建议!

谢谢,

汤姆

修改

根据MrLink的建议,在SELECT查询中添加“TOP 1”可将性能从310提高到约585个事务/秒

编辑2:

Arash N建议选择查询“WITH(NOLOCK)”,这会大大提高性能!我现在看到大约2500次交易/秒

编辑3:

我在.NET方面做的另一个小优化帮助我获得了另外150个事务/秒。将(reader.Read())更改为if(reader.Read())令人惊讶地产生了很大的不同。在平均我现在看到2719次交易/秒

9 个答案:

答案 0 :(得分:1)

需要考虑的一些事项。

首先,您没有关闭服务器连接。 (cnn.Close();)最后,它将被垃圾收集器关闭。但在此之前,您每次都要创建一个全新的数据库连接,而不是从连接池中收集一个连接。

其次,你在Sql Server中有一个覆盖AccountID和Symbol列的索引吗?

第三,虽然accountId和int很好而且速度很快。 Symbol列是varchar(25)总是要慢得多。你能把它改成一个int标志吗?

答案 1 :(得分:1)

确保您的数据库连接实际上是池。如果你看到cnn.Open的瓶颈,他们似乎很有可能没有被合并。

答案 2 :(得分:1)

尝试在SELECT语句中使用WITH(NOLOCK)来提高性能。这将选择行而不锁定它。

SELECT p.ID, p.A, p.B, p.C, p.D, p.E, p.F FROM [MyData] WITH(NOLOCK) AS p WHERE p.AccountID = @AccountID AND p.Symbol = @Symbol

答案 3 :(得分:1)

  

我希望在一个循环中运行GetMyData时,能够达到1000多个事务/秒

你要求的是GetMyData在不到1毫秒的时间内运行 - 这只是毫无意义的优化!至少这种方法涉及到数据库服务器的往返(可能涉及网络访问) - 如果您的查询是SELECT 1,您将无法更快地使用此方法。

如果您真的要求每秒发出更多请求,那么答案就是使用多个线程或购买速度更快的PC。

您的代码完全没有问题 - 我不确定您在哪里看到人们每秒管理10,000多个事务,但我确信这必须涉及多个并发客户端访问同一个数据库服务器而不是单个线程管理在不到10秒的时间内执行查询!

答案 4 :(得分:0)

您的方法经常被调用吗?您是否可以批量处理您的请求,这样您就可以打开连接,创建参数,获得结果并在重新关闭整个事件之前重复使用它们进行多次查询?

答案 5 :(得分:0)

如果数据不经常无效(更新),我会实现缓存层。这是获得性能的最有效方法之一(如果使用得当)。

答案 6 :(得分:0)

您可以使用输出参数而不是select,因为总是有一行。

您也可以提前创建SqlCommand并重新使用它。如果您在单个线程中执行大量查询,则可以继续在同一连接上执行它。如果没有,您可以创建它们的池或执行cmdTemplate.Clone()并设置Connection。

答案 7 :(得分:0)

尝试重新使用命令,然后先Prepare将其命名。

我不能说这肯定会有所帮助,但似乎值得一试。

答案 8 :(得分:0)

没有特别的顺序......

  • 您(或您的DBA)是否检查过您的存储过程正在执行的执行计划? SQL Server是否缓存了伪造的执行计划(由于奇怪的参数或旧的统计数据)。

  • 数据库中统计信息的更新频率是多少?

  • 您是否在存储过程中使用临时表?如果是这样,他们是否预先创建。如果没有,您将进行大量重新编译,因为创建临时表会使执行计划无效。

  • 您使用的是连接池吗?打开/关闭SQL服务器连接是一项昂贵的操作。

  • 您的表格是否聚集在accountID和Symbol?

...最后

  • 您是否有理由按帐户和符号点击此表,而不是仅仅一次性检索整个帐户的所有数据?