应用调优:改善SQL Server数据库性能

日期: 2011-11-23 作者:Roman Rehak翻译:冯昀辉 来源:TechTarget中国 英文

当你开发的SQL Server应用程序有数百用户并发访问,使用的数据库有百万行级数据时,把那些应用程序做到尽可能高效是至关重要的,这样硬件才能跟得上负载处理。这一点既适用于数据库,也适用于客户端应用程序代码。本文将指导DBA来对你的应用程序进行调优,以改善SQL Server性能。   索引就是一切   大部分人,甚至是数据库经验很少的人群也会认同索引对于开发高效数据库应用程序的重要性。

然而实际上,索引常常被忽略或者不恰当地使用。通常,高级软件工程师也会开发索引使用不当的应用程序。   没有合适的索引,SQL Server不得不扫描表中所有数据来查找匹配行。你可以想象没有目录要在一本书中找到特……

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

当你开发的SQL Server应用程序有数百用户并发访问,使用的数据库有百万行级数据时,把那些应用程序做到尽可能高效是至关重要的,这样硬件才能跟得上负载处理。这一点既适用于数据库,也适用于客户端应用程序代码。本文将指导DBA来对你的应用程序进行调优,以改善SQL Server性能。

  索引就是一切

  大部分人,甚至是数据库经验很少的人群也会认同索引对于开发高效数据库应用程序的重要性。然而实际上,索引常常被忽略或者不恰当地使用。通常,高级软件工程师也会开发索引使用不当的应用程序。

  没有合适的索引,SQL Server不得不扫描表中所有数据来查找匹配行。你可以想象没有目录要在一本书中找到特定词语会多么困难。每次你要查找一些信息时,你不得不从头到尾把整本书读完。本质上,SQL Server每次在没有索引的大表中查找数据时,做的就是同样的事情。所以一般来说,你应该在“WHERE”语句中带上有索引的列。

  代码问题

  批量处理和批量导入应用程序常常读取和处理大量输入数据,并把它移动到目标数据库中。这些应用程序处理百万级数据记录并不少见。我见过开发人员在这类应用程序中犯的一个错误就是像开发常规应用程序一样写代码,一次处理一个更新作为自我完备的代码段。

  例如,对于由ADO.NET处理的每一行,应用程序会启动一个“while”循环:创建连接“connection”对象,连接数据库,创建“command”对象,用新创建的参数连接填充并发起数据库调用,然后循环运行时会清理所有这些对象。在批量处理的应用程序中,所有这些初始化和清理的代价很昂贵。做一次就足够了。

  为了获得最大化效率,应该把初始化和清理代码移到循环体外部,并尽可能收紧循环体。创建和初始化ADO.NET对象(比如,连接connection,命令command和参数parameter)不应该放到处理数据的“while”循环体中。创建和初始化ADO.NET对象只需要执行一次,然后就是在处理循环中修改参数值并更新数据库。在末尾做清理工作时,也放到循环体外部。

  请记住,当你在处理百万行级数据时,甚至几毫秒的差异也会造成很大差异。当你按处理记录行数做天文数字倍增时,你可能就会节约小时级的处理时间。

  谨慎使用COUNT(*)

  这是另一个低效率的编码方式,开发人员经常会做:“如果‘SELECT COUNT(*)’的结果大于零,就做某些事情。”如果你更仔细地考虑它,你就会明白我们希望的是“如果至少有一行满足了条件,就做某些事情。”这里使用“COUNT(*)”的问题是SQL查询将计算出所有匹配的行;相反,我们可以使用“EXISTS ”查询来在找到第一行匹配时就停止查找。所以,要记住这个细微的差异,只在需要知道确切记录数量时才统计所有数据。如果所有你需要做的只是检查是否至少存在一行匹配,那就使用“EXISTS ”吧。

  让查询中的数据类型保持一致

  在编写带有参数的Transact-SQL和ADO.NET代码时,把查询中的数据类型与表列的数据类型相匹配很重要。在一些情况下,SQL Server会自动为你做隐式数据类型转换(例如,把数值类型转换为字符串类型)。但是,你可能没有意识到的是,虽然数据类型转换不会影响结果,但是SQL Server可能不能使用查询列已经存在的索引了。

  我们来举一个例子,我们看看微软公司自带的AdventureWorks 数据库。在“Employee ”表中,有名为“NationalIDNumber”的列;数据库中它定义的数据类型是变长数据类型“NVARCHAR(15)”。该列创建了索引,所以如果使用唯一ID进行搜索,SQL Server应该能执行快速查找。现在我们看看下面两个可以返回相同结果的查询语句:

  查询1:

  SELECT
  * FROM [HumanResources].[Employee]
  WHERE NationalIDNumber = N'233069302'

  查询2:

  SELECT
  * FROM [HumanResources].[Employee]
  WHERE NationalIDNumber = 233069302

  图1展示了两个查询的执行计划。(在每个窗口中,“查询代价”展示了查询花费执行时间的百分比,每个步骤的百分比显示在查询行的下方。)

  图1。这个执行计划显示,当数据类型匹配时(上面的窗口),SQL Server会执行索引搜索查找匹配数据。当数据类型不匹配时(第二个查询),SQL Server使用更低效的索引扫描。

  在第一个查询中,我们使用“NVARCHAR ”字符串搜索N‘233069302’,所以查询的数据类型与表中的数据类型是相匹配的。SQL Server使用“NationalIDNumber ”列现存的索引,执行索引查找。这就给我们提供了快速查找的效率。

  在第二个查询中,我们使用“integer”,‘233069302’,所以在查询和表的数据类型之间存在类型不匹配。随后,SQL Server会转换表中每一行的该列值,从“NVARCHAR ”转换为“INTEGER ”,再执行比较,这种方式会扫描表中所有行。它仍然会使用索引,因为在索引页扫描所有国家ID比在数据页扫描要更快,但是扫描需要更多的处理,产生的是相同的结果。

  在这个特定的数据库中,两个查询执行的差异不是太大(整体执行时间是54%与46%),但是如果表中有数百万行数据,我们可以说执行时间就会花费很多秒,而不是毫秒级。在这个查询中的差别是很细小的,但是如果程序员认为表中数据类型就是存储为整型,那就容易犯错误而不做仔细检查。

  为你的数据库建立索引可以使应用程序运行更快,响应更迅速,有效编码可以缩短处理时间。当你使用较小的数据库,并且你的前端应用程序并不会有太多并发用户访问时,低效率并不会那么明显易见。但是,当数据堆积,你的应用程序使用变得更加频繁时,数据库和应用程序就会变慢,直到最终不可用,用户将会超时,你的客户也会不高兴。遵守这些编码和数据库效率时间,心中牢记扩展性为应用程序编码才能最终提高SQL Server性能。

相关推荐