2013-02-13 50 views
10

我需要从以下你利弊/大师确认/解释,因为我的团队告诉我,“没关系”,它的fustrating我:)SQL性能,净优化VS最佳实践

背景:我们的主要MVC3/.Net4网络应用程序正在使用SQL Server 2008。我们在任何特定点都有大约200多个并发用户。服务器正在极其困难地工作(锁定,超时,整体缓慢),并且我尝试应用我在我职业生涯和最后一次MS认证课程中学到的知识。它们都是我们已经完成的东西(“关闭SQL连接STAT”),我试图向我的团队解释这些“小东西”,尽管不是单独产生影响,但最终加起来就是

我需要知道,如果下面做会影响性能,或者如果它只是“最佳实践”

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

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.连接池

我总是听说建立连接池能显著加快网站(至少净W/MSSQL)。 我建议大家添加以下我们的ConnectionStrings在web.config:

...... “池= TRUE;闵池大小= 3;最大池大小= 100;连接 超时= 10;”。 ..

他们的观点是.Net/MSSQL已经在后台设置了连接池,并且不需要放在我们的web.config中。对或错?为什么所有其他网站都说如果已经设置好了,应该添加最优性能?

3.尽量减少通话#到DB

自带的默认的.Net MVC项目是很好的作用/会员供应商 - 它的方便和完成大部分跑腿的为您服务。但是这些家伙正在认真使用UsersInRoles()并且像全局变量一样自由使用它(每次调用这个方法时它都会触发DB)。 我创建了一个“用户对象”,用于在每个页面加载上加载所有角色(以及其他一些用户内容,例如GUID等),然后查询该对象是否具有角色。

网站的其他部分有FOR语句循环超过200次,每次传递20-30个SQL查询=超过4,000次数据库调用。它在几秒钟内就可以做到这一点,但我想要做的是将20-30个DB呼叫合并为一个,这样就可以让ONE呼叫200次(每个循环)。 但由于SQL事件探查器说查询花费了“0秒”,所以它们的参数是如此之快以至于服务器可以处理这些大量的数据库查询。

我的想法是“是的,这些查询运行速度很快,但它们正在杀死整个SQL服务器的性能。” 这可能是一个促成因素吗?我是否担心什么,或者这是服务器整体性能问题的一个(显着)影响因素?

4,其他代码优化

想到的是使用StringBuilder VS一个简单的字符串变量的第一个。我明白为什么我应该使用StringBuilder(特别是在循环中),但他们说这并不重要 - 即使他们需要编写10k +行,他们的观点是性能增益并不重要。因此,总而言之,就是我们学习并钻进我们的所有东西(“最小化范围!”)只是“最佳实践”,没有真正的性能收益,或者它们都对真实/可衡量的性能有所贡献失利?

编辑 *** 谢谢你们所有的答案!我有一个基于你的答案的新的(第5个)问题: 他们实际上不使用“USING”,那么这意味着什么呢?如果自动发生连接池,是否将池中的连接捆绑在一起,直到GC出现?是否有可能每个开放的连接到SQL服务器增加了一点负担,并放慢了服务器?

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

我真的很感谢你们的帮助。即实现IDisposable并按住inmanaged资源也实现finilizer,确保GC过程中调用Dispose再次感谢

+0

不要说研究并不重要,但是对SO的大师确实提供了很多见解......研究他们说的是非常多的研究 – 2013-02-13 22:37:53

+0

@ JakeWilson801来自MS的文档并不总是最好的来源。 (编辑:或者甚至是一个很好的源码) – 2013-02-13 22:38:25

+0

重新使用字符串生成器而不是连接字符串 - 如果你要连接字符串一次(即'var s =“a”+“b”'),那么字符串会更有效率,你需要记住,虽然是一个字符串实例是不可变的,所以在一个循环例如'string s =“a”; for(int i = 1,i <1000; i ++){s + =“a”;}'你为每个循环创建一个新的字符串实例,这会影响内存分配并影响整体性能(无论是否显着将取决于连接的数量)。 – GarethD 2013-02-13 22:53:08

回答

5

分公司的代码,进行更改&基准+简介它针对当前的代码库。那么你会有一些证据来支持你的说法。

至于你的问题,这里有云:

  1. 你应该总是手动处置它们实现IDisposable类,GC将不会真正调用但如果处置类也实现了一个终结,然后它会调用但是在大多数实现中,终结器只是清理非托管资源。

  2. 的确,.NET框架已经做了连接池,我不确定默认值是什么,但连接字符串值只是在那里让你改变它们。

  3. SQL语句的执行时间只是故事的一部分,在SQL事件探查器中,您将看到数据库引擎执行查询所用的时间,您错过的时间以及所需的时间Web服务器连接到数据库服务器并从数据库服务器接收结果,因此在查询可能很快时,您可以通过批量查询节省大量的网络延迟时间。

  4. 这个人是一个很好的做一些分析上证明了字符串生成器使用串联额外的内存。

+1

根据[本站点](http://www.connectionstrings.com/articles/show/all-sql-server-connection-string-keywords),连接池的默认值分别为0,最大100。 – 2013-02-13 23:09:12

+0

+1这个答案在解决每个问题上做得最好。我也喜欢这个分支和基准的建议。 – 2013-02-13 23:11:01

+0

#1 - 你们许多人都说过同样的事情 - GC不会马上清理它。那么,这是否会连接其中一个连接池?可能有几百个这样的开放连接会导致服务器速度下降?对于#3,你给了我一个巨大的争论点。我会尝试隔离连接时间并将其添加到每次点击的2000+ db调用中的每一个,并查看出现的结果 - 好主意,谢谢! – Losbear 2013-02-13 23:17:59

3
  1. 对象,问题是当它被调用时,GC会占用大量的时间做它和你在这之前需要这些资源。使用完成后立即致电处理。

  2. 您可以修改参数在webconfig集中的,但其在默认情况下,现在,如果你保持默认参数,你没有得到什么

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

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

+1

另外:有一个终结器(并且SuppressFinalize没有被调用)的对象需要两个垃圾收集,直到它们被完全删除。 – 2013-02-13 22:38:30

+0

除了我自己的评论:具有终结器并正确实现Disposable模式的类型将在它们的Dispose函数中调用SuppressFinalize。通过配置这些类型,第二次垃圾收集的需求就被移除了。 (这应该更关注我的第一条评论) – 2013-02-13 22:46:05

1

嗯,我不是大师,但我确实有一个建议:如果他们说你错了,告诉他们,“证明它!给我一个测试!给我看4000个电话只是最快可以打200个电话,并且对服务器有相同的影响!“

还有其他的东西。如果你无法让他们证明你是正确的,那么证明他们是错误的,并且有明确的,有据可查的测试,证明你说的是正确的。

如果他们还没有开到确凿的证据,从自己的服务器收集,使用代码,他们可以看一下,检查,那么你可以在该团队浪费你的时间。

+0

我不能说“证明它”(尽可能多的),因为应用程序是在我加入之前编写的。所以现在我的负担就是向他们证明为什么他们应该回去修复他们的代码:) – Losbear 2013-02-13 23:19:01

+0

@Losbear这可能是一场艰苦的战斗!但是你打算进入的方向(在其他评论中)听起来很不错。测试并再次测试,并向他们显示硬编号。祝你好运! – 2013-02-14 18:04:27

0

的使用条款只是语法糖,你基本上是在做

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

处置很可能迟早要被称为是垃圾收集的对象时,但前提是框架的程序员做了很好的实施the disposable pattern的工作。所以,这里对你的同事的论据是:

我),如果我们养成使用我们使用的习惯,一定要释放非托管资源,因为不是所有的框架程序员是聪明实行一次性模式。

II)是的,GC将最终清除该对象,但它可能需要一段时间,具体取决于该对象是几岁。 Gen 2 GC清理每秒只进行一次。

那么短:

  1. 见上

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

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

  4. 过早的优化是所有罪恶的根源。首先获得#1和#3。使用SQL profiler和db特定方法(添加索引,对它们进行碎片整理,监视死锁等)。

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

总是测量你的改进,不要改变没有证据的代码!

+0

同意 - 我的团队和我同意的一件事是我们都不想将太多的工作投入到没有去做的事情中帮助那么多;如将字符串变量转换为字符串对象LOL。我认为最终,只有来自Profiler的硬数据才能说服这些家伙:) THanks Bogdan – Losbear 2013-02-13 23:22:26

2

我认为你在这里有两个单独的问题。

  1. 代码的性能
  2. 性能SQL Server数据库的

SQL服务器

你有到位的SQL Server中的任何监控?你知道具体哪些查询会导致死锁吗?

我会读this article on deadlocks并考虑安装辉煌的Who is active以了解您的SQL Server中究竟发生了什么。您也可以考虑安装Brent Ozar的sp_Blitz。这应该给你一个关于你的数据库正在发生什么的好主意,并给你一些工具来首先解决这个问题。

其他代码发出

我真的不能把我的头顶部的其他代码的问题发表评论。所以我会先看看SQL服务器。

记住

  1. 监视器
  2. 确定问题
  3. 简介
  4. 修复
  5. 转到1
+0

是的,我看过SQL Profiler在实时服务器上,并试图告诉他们“看,这一点击2000+ !”但他们的论点是“但它在2秒内完成了所有2k电话”。我试图超越这一点,并用“这2秒钟加起来”来抵消它,但我并不是100%肯定的,因为那2秒钟与200个其他并发用户混合在一起。 – Losbear 2013-02-13 23:14:55

4

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

0

我最近在处理一个在我们的web应用程序和电子邮件提供商发送电子邮件时发生协议错误。但不是马上。

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

而且我注意到,这个经常带着2分钟被点击“发送”按钮后,...

不用说,现在的代码正确实现两者的SmtpClientMailMessage实例using块。

只是聪明人的话......

+0

2分钟比我认为的更好 - 我认为GC每5或10分钟循环一次(这真的很糟糕)。感谢给我一个想法(我知道它可以是+或 - 几分钟)GC通过的频率。 – Losbear 2013-02-13 23:24:27

0

1已远高于(我同意但它很好地处置,并发现它是一个很好的做法)解决。

2是从以前版本的ODBC持有一点,其中SQL Server连接是独立配置关于池。它曾经是非默认的;现在它是默认的。

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

3听起来像是最合乎逻辑的集中注意力,对我来说。我尽可能快地关闭数据库连接,并尽可能减少最少的通话次数。如果您使用的是LINQ,请将所有东西都拉成IQueryable或其他东西(列表,数组等等),以便您可以操纵它&可以创建任何您需要的UI结构,同时在任何该hokum之前释放连接。

所有这一切都说,这听起来像你需要花一些更多的质量时间与探查器。而不是看每次执行的时间量,看看处理器的内存使用情况。仅仅因为他们快,并不意味着他们不是“饿”的处决。

1

在的只是在重复别人在这里所说的风险,这是我对此事2C

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

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

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

为了解决您的第5个问题 - 我不确定,但我猜想任何不是自动处理的SqlConnection(通过使用)都会被视为仍处于“活动”状态,并且不再可用。这就是说 - 服务器上的连接开销很低,除非连接实际上在做什么 - 但是你可以再次通过使用SQL性能计数器来证明这一点。

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

+0

谢谢斯蒂芬。是的,我打算对此进行外交,大声笑:)我怀疑#3,但我想我想知道这些问题集体会产生什么样的影响 - 或者这是一个可能导致整体缓慢的问题。再次感谢您的2c - 当我明天运行数字时,我会发布我的发现:) – Losbear 2013-02-14 01:07:57