C# C SQL Server与多个用户的连接问题-性能降级,带池

C# C SQL Server与多个用户的连接问题-性能降级,带池,c#,sql,sql-server,web-services,web,C#,Sql,Sql Server,Web Services,Web,我有一个问题,我希望是一个简单的解决办法 我有一个C web服务,通过JSON调用web方法与之交互,该web方法使用下面的代码与数据库交互 连接字符串: <add name="MainConnection" connectionString="SERVER=10.218.147.71;DATABASE=******;UID=******-web;PWD=******;Pooling=True;Min Pool Size=25;Max Pool Size=250;"

我有一个问题,我希望是一个简单的解决办法

我有一个C web服务,通过JSON调用web方法与之交互,该web方法使用下面的代码与数据库交互

连接字符串:

<add name="MainConnection" 
     connectionString="SERVER=10.218.147.71;DATABASE=******;UID=******-web;PWD=******;Pooling=True;Min Pool Size=25;Max Pool Size=250;" 
     providerName="System.Data.SqlClient" />
方法代码:

public List<MatchmakingSessions> GetMatchmakingSessionsWithSearchQuery(string mThisQuery = "") {
    List<MatchmakingSessions> matchmakingsessionsList = new List<MatchmakingSessions>();

    SqlConnection mConnection;
    SqlCommand mCommand;
    try {
        using (mConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MainConnection"].ConnectionString)) {
            mCommand = new SqlCommand("SELECT * FROM [MatchmakingSessions] " + mThisQuery, mConnection);

            if (mConnection.State == ConnectionState.Closed) {
                mConnection.Open();
            }

            SqlDataReader mReader = mCommand.ExecuteReader();

            while (mReader.Read()) {
                if (mReader.HasRows) {
                    MatchmakingSessions mMatchmakingSessions = new MatchmakingSessions();
                    mMatchmakingSessions.SessionID = (mReader["SessionID"] is DBNull) ? 0 : Int32.Parse(mReader["SessionID"].ToString());
                    //More DB calls to set properties...
                    matchmakingsessionsList.Add(mMatchmakingSessions);
                }
            }
            mReader.Close();
        }
    }
    catch (Exception x) {
        if (!GGErrorHandler.ContainsRegularTypes(x.Message)) {
            BusinessHelper.SendMailMessage(string.Format("<b>Error Message</b>: <br /><br />{0}</br><b>Stack Trace</b>: <br />{1}<br />", x.Message, x.StackTrace));
            throw new Exception(GGErrorHandler.GetUserFriendlyError("DefaultErrorMessage", ErrorSource.WebAPI, x.Message));
        }
        else
            throw new Exception(GGErrorHandler.GetUserFriendlyError(x.Message, ErrorSource.WebAPI, x.Message));
    }
    finally {
        mConnection.Close();
        mCommand.Dispose();
    }

    return matchmakingsessionsList;
}
我运行了一个压力测试,只有大约200个用户调用相同的方法,每个用户大约间隔1秒,所有用户同时调用,我开始得到错误:

超时已过期。从池中获取连接之前经过的超时时间。发生这种情况的原因可能是所有池连接都在使用中,并且已达到最大池大小

最终导致整个web服务崩溃

在数据库上运行sp_who2时,我看到大约250个连接。运行iisreset后,它将下降到40个连接。然后在压力测试期间,DB上的CPU达到100%,并最终导致上述超时问题。web服务似乎也会受到高延迟的影响,然后在简单方法交互上最终会出现500个错误


我在管理我的连接方面是否完全不正确?

你可以试着处理掉mReader。从技术上讲,当它超出范围时,它应该下降,但更有趣的事情发生了。领导处置

好吧,也许现在这不是你的问题,但是以这种方式连接字符串的公共WCF服务从一开始就注定了失败。你听说过Sql注入吗?上面的特定方法不是web方法。调用此方法的web方法负责创建查询;此查询中不允许用户输入字符串。您分析过该查询了吗?可能存在过多的锁定阻塞问题。设置SQL配置文件并再次运行压力测试。收集性能计数器,检查磁盘队列长度是否达到峰值,查询是否正确索引等。我确实运行了一个探查器,它对索引有很多建议。但是,在SqlServer性能计数器的.NET数据提供程序上,一个框上的NumberOfPooledConnections当前为8,NumberOfFreeConnections为0-要么计数器出错,要么连接没有释放回池中,要么我没有正确读取?嗯。。更进一步说,当我对500个用户进行压力测试时,我观察了这些计数器,我看到PooledConnections的数量跳到了50,这是我在这个连接字符串中设置的最大值,然后不久,它会慢慢下降到5左右。。我已将最小值设置为0。。因此,基于这一点,它似乎会起作用,也解释了我上面的错误,为什么没有免费连接。。duh-lolAs Steve指出,因为min被设置为0,所以您不应该以这种方式运行查询。至少让查询包含一个参数,然后发送并添加该参数。它会在一定程度上保护您。尝试将阅读器包装在使用块中;关闭它;处置;以及命令本身。似乎没什么区别。我正在尝试设置SQLDependency缓存,但是运气不太好-所以我想只是基于查询创建一个缓存对象,并在其他web服务方法之一更新表时使缓存无效,即使如果触发器能够正确工作,这将非常棒-不确定内置SQL依赖项为什么不能工作。但是,回到主题-在查询中分配参数是否会使SQL客户端或SQL本身对正在发送的参数进行任何预处理?既然我用它来指定WHERE中的条件,并应用ORDER BY语句,甚至是内部联接,那么它不仅仅与在发送到SQL之前在命令中连接字符串相同吗?是的。你至少会把它限制在一个可能的限度内。像命令终结者之类的东西很可能不被允许通过。另一方面,我并不特别推荐,你可以随时运行垃圾收集器,看看它是否有助于清理问题-但你仍需要弄清实际问题的根源GC.Collect。我怀疑问题在于,当压力测试中数千个客户端每秒调用多个方法时,所有这些方法都需要DB连接,我实际上已经超过了池的最大限制-我如何正确地扩展这个问题以拥有多个池?我是否应该创建另一个网站/应用程序池以进一步实现负载平衡?我需要额外的web服务器吗?