SQL性能,.Net优化与最佳实践

时间:2013-02-13 22:23:49

标签: c# .net sql-server asp.net-mvc sql-server-2008

我需要你的专业人士/大师的确认/解释,因为我的团队告诉我“这没关系”,这让我感到很沮丧:)

后台:我们的主要MVC3 / .Net4网络应用程序正在使用SQL Server 2008。我们在任何给定点上都有大约200多个并发用户。服务器受到极大的打击(锁定,超时,整体缓慢),我正在尝试应用我在整个职业生涯和最后一次MS认证课程中学到的东西。他们是我们所有人都在钻的东西(“关闭SQL连接STAT”),我试图向我的团队解释这些“小东西”,虽然不是唯一一个有所作为,但最终还是加起来。 / p>

我需要知道以下内容是否会对性能产生影响,或者它是否只是“最佳实践”

1。使用“USING”关键字。 他们的大部分代码都是这样的:

public string SomeMethod(string x, string y) {
    SomethingDataContext dc = new SomethingDataContext();
    var x = dc.StoredProcedure(x, y);
}

虽然我试图告诉他们USING会更快地关闭/释放资源:

using (SomethingDataContext dc = new SomethingDataContext()) {
    var x = dc.StoredProcedure(x, y);
}

他们的论点是GC在代码完成执行后做了很好的清理工作,因此USING没有产生巨大的影响。是真还是假?为什么?

2。连接池

我一直听说设置连接池可以显着加快任何网站的速度(至少.Net w / MSSQL)。 我建议我们在web.config中添加以下连接字符串:

  

...“Pooling = True; Min Pool Size = 3; Max Pool Size = 100; Connection   超时= 10;” ...

他们的论点是.Net / MSSQL已经在幕后建立连接池,而不必放入我们的web.config。对或错?为什么每个其他网站都说如果已经设置了池,那么应该添加池以获得最佳性能?

第3。最小化对DB的调用次数

默认.Net MVC项目附带的角色/成员资格提供程序很不错 - 它很方便,可以为您完成大部分工作。但是这些人正在认真地使用UsersInRoles()并像一个全局变量一样自由地使用它(每次调用这个方法时它就会击中数据库)。 我创建了一个“用户对象”,它在每个页面加载(以及一些其他用户的东西,如GUID等)上预先加载所有角色,然后查询该对象是否具有该角色。

网站的其他部分有FOR语句,循环次数超过200次,并且每次传递都会进行20-30次sql查询=超过4,000次数据库调用。它以某种方式在几秒钟内完成,但我想要做的是将20-30个DB调用合并为一个,这样它就可以进行200次调用(每个循环)。 但是因为SQL分析器说查询花了“0秒”,所以它们的论点是它如此快速和小,以至于服务器可以处理这些大量的数据库查询。

我的想法是“是的,这些查询运行速度很快,但它们会破坏整个SQL服务器的性能。” 这可能是一个促成因素吗?我是否担心什么,或者这是服务器整体性能问题的重要因素?

4。其他代码优化

首先想到的是使用StringBuilder vs一个简单的字符串变量。我理解为什么我应该使用StringBuilder(特别是在循环中),但是他们说这没关系 - 即使他们需要写10k +行,他们的论点是性能增益无关紧要。

总而言之,我们所学到的所有东西都已经深入到我们身上(“最小化范围!”)只是“最佳实践”而没有真正的性能提升,或者它们都会导致实际/可衡量的性能损失?

修改 *** 谢谢你们所有的答案!我根据你的答案提出了一个新的(第五个)问题: 事实上他们并没有使用“USING”,那么这意味着什么呢?如果连接池自动发生,它是否会从池中连接到GC到来之前?是否可能每个与SQL服务器的开放连接都会给服务器增加一点负担并减慢它的速度?

根据你的建议,我计划对连接时间做一些严格的基准测试/记录,因为我怀疑a)服务器很慢,b)他们没有关闭连接,c)Profiler说它在0秒内运行,缓慢可能来自连接。

我真的很感谢你的帮助。再次谢谢

9 个答案:

答案 0 :(得分:5)

对代码进行分支,进行更改和更改基准测试+将其与当前代码库进行配置。然后你会得到一些证据来支持你的说法。

至于你的问题,请点击:

  1. 你应该总是手动处理实现IDisposable的类,GC实际上不会调用dispose,但是如果类也实现了终结器,那么它将调用终结器,但是在大多数实现中它们只是清理非托管资源。

  2. .NET框架确实已经建立了连接池,我不确定默认值是什么,但连接字符串值只是允许你改变它们。

  3. SQL语句的执行时间只是故事的一部分,在SQL分析器中,您将看到数据库引擎执行查询所花费的时间,您所缺少的是它需要的时间Web服务器连接到数据库服务器并从数据库服务器接收结果,因此查询可能很快,您可以节省大量的IO&批量查询的网络延迟。

  4. 这个是一个很好的一个,可以进行一些分析,以证明串联在字符串构建器上使用的额外内存。

答案 1 :(得分:4)

奥耶。当然,您不能让GC关闭您的数据库连接。 GC可能不会发生很长时间......有时几个小时后。一旦变量超出范围,它就不会立即发生。大多数人使用IDisposable使用(){}语法,这很好,但至少在某些地方,某处需要调用connection.Close()

答案 2 :(得分:3)

  1. 实现IDisposable并保持inmanaged资源的对象也实现了一个finilizer,它将确保在GC期间调用dispose,问题是在调用它时,gc可能需要花费大量时间来完成它而你在此之前,migth需要这些资源。一旦完成,使用就会调用dispose。

  2. 您可以在webconfig中修改池的参数,但现在默认为on,所以如果保留默认参数,则无法获得任何内容

  3. 您不仅要考虑执行查询需要多长时间,还要考虑应用程序服务器和数据库之间的连接时间,即使它在同一台计算机上也会增加开销。

  4. StringBuilder不会影响大多数Web应用程序的性能,只有当你将2次连接到相同的字符串时才会很重要,但我认为使用它是一个好主意,因为它更容易阅读。

答案 3 :(得分:2)

我认为你在这里有两个不同的问题。

  1. 您的代码的效果
  2. SQL Server数据库的性能
  3. SQL Server

    您是否对SQL Server进行了任何监控?您是否具体了解导致死锁的查询?

    我会阅读this article on deadlocks并考虑安装辉煌的Who is active以了解SQL Server中的实际情况。您也可以考虑安装Brent Ozar的sp_Blitz。这应该可以让您对数据库中发生的事情有一个很好的了解,并为您提供解决该问题的工具。

    其他代码问题

    我无法真正评论其他代码问题。所以我先看看SQL服务器。

    <强>记住

    1. 监视器
    2. 识别问题
    3. 资料
    4. 修复
    5. 转到1

答案 4 :(得分:1)

嗯,我不是大师,但我确实有一个建议:如果他们说你错了,告诉他们,“证明它!给我一个测试!告诉我4000个电话就像200个一样快调用并对服务器产生同样的影响!“

同样的其他事情。如果你不能让他们证明你是对的,那就证明他们是错的,有明确的,有文件记录的测试证明你所说的是正确的。

如果他们甚至没有打开证据,从他们自己的服务器收集,他们可以查看和检查代码,那么你可能会浪费你的时间在那个团队。

答案 5 :(得分:1)

冒着重复其他人所说的话的风险,这是关于此事的我的2c

首先,你应该仔细挑选你的战斗......我不会在所有4点与你的同事开战,因为一旦你未能证明其中一个,它就结束了,从他们的角度来看他们是对,你错了。 还要记住,没有人喜欢被告知他们美丽的代码是一个丑陋的婴儿,所以我认为你将是外交 - 不要说“这很慢”,说“我找到了一种方法,使这更快“....(当然你的团队可能非常合理,所以我也基于我自己的经验:)所以你需要选择上面4个区域中的一个来解决。

我的钱在#3上。 1,2和4可以有所作为,但根据我自己的经验,并没有那么多 - 但你在#3中所描述的听起来像是因为可怜的旧服务器的千张纸张而死!查询可能执行速度很快,因为它们已经参数化,因此它们被缓存了,但是你需要记住,探查器中的“0秒”可能是900毫秒,如果你看到我的意思...加上许多事情开始变慢;这也可能是锁的主要来源,因为如果这些嵌套查询中的每一个都反复敲击同一个表,无论它运行得多快,根据您提到的用户数量,您肯定会有争用。 获取SQL并在SSMS中运行它,但包括客户端统计信息,这样您不仅可以查看执行时间,还可以查看发送回客户端的数据量;这将使您更清楚地了解所涉及的开销类型。

真的唯一可以证明这一点的方法是像其他人提到的那样设置测试和测量,但也肯定也会在服务器上运行一些分析 - 锁,IO队列等,以便你可以表明,不仅你的方式更快,而且它减轻了服务器上的负担。

要触及你的第五个问题 - 我不确定,但我猜想任何未自动处理的SqlConnection(通过使用)都被视为仍然“活跃”,并且不再可以从池中获得。话虽如此 - 服务器上的连接开销非常低,除非连接实际上正在做任何事情 - 但您可以通过使用SQL性能计数器再次证明这一点。

祝你好运,迫不及待地想知道你是怎么过的。

答案 6 :(得分:0)

using子句只是语法糖,你基本上是在做

try
{
    resouce.DoStuff();
}
finally
{
     resource.Dispose()
}

当对象被垃圾收集时,无论如何都可能会调用Dispose,但前提是框架程序员在实现the disposable pattern时做得很好。所以这里针对你同事的论点是:

i)如果我们养成使用的习惯,我们确保释放非托管资源,因为并非所有框架程序员都能够实现一次性模式。

ii)是的,GC最终将清理该对象,但可能需要一段时间,具体取决于该对象的年龄。 gen 2 GC清理每秒只进行一次。

简而言之:

  1. 见上文

  2. 是的,池默认设置为true,最大池大小设置为100

  3. 你是对的,绝对是推动改进的最佳领域。

  4. 过早优化是万恶之源。首先获得#1和#3。使用SQL 分析器和数据库特定方法(添加索引,对它们进行碎片整理,监视死锁等)。

  5. 是的,可能。最好的方法是测量它 - 查看perf计数器SQLServer:General Statistics - User Connections; here是一篇描述如何操作的文章。

  6. 始终衡量您的改进,不要在没有证据的情况下更改代码!

答案 7 :(得分:0)

我最近处理的是我们的网络应用程序和我们的电子邮件提供商之间的交互中的错误。发送电子邮件时,发生协议错误。但不是马上。

我能够确定错误仅在SmtpClient实例关闭时发生,这是在SmtpClient处置时发生的,这只发生在垃圾收集期间。

我注意到点击“发送”按钮后经常需要两分钟 ...

毋庸置疑,代码现在可以为usingSmtpClient实例正确实施MailMessage块。

对智者说一句话......

答案 8 :(得分:0)

1已经在上面得到了解决(我同意它处理得很好,然而,发现这是一个很好的做法)。

2与以前版本的ODBC有点相似,其中SQL Server连接是独立配置的。它曾经是非默认的;现在它是默认的。

对于3和4,4不会影响SQL Server的性能 - StringBuilder可能有助于加快UI中的进程,当然,这可能会更快地关闭SQL资源,但它们不会减少SQL Server的负载。

对我来说,3听起来像是最合乎逻辑的地方。我尝试尽快关闭我的数据库连接,并尽可能少地调用。如果您正在使用LINQ,请将所有内容放入IQueryable或其他内容(列表,数组等),以便您可以对其进行操作。构建您需要的任何UI结构,同时在任何该hokum之前释放连接。

所有这些都说,听起来你需要花更多的时间在探查器上。而不是查看每次执行所花费的时间,而不是查看处理器和处理器。内存使用情况。仅仅因为他们的速度快并不意味着他们不是“饥饿”的执行。

相关问题