在过去十年里,很多复杂的企业应用都是用Microsoft SQL Server进行开发和部署的。如今,SQL Server已经成为现代业务应用的基石,并且它还是很多大公司业务流程的核心。SQL Server的应用范围很广,包括生产过程中的业务线应用,内部客户关系管理和决策支持系统,以及面向用户的电子商务和网络自服务应用等。因此,SQL Server性能和可伸缩性具有很高的优先级,而且提供最优的SQL Server性能和扩展性也是所有SQL Server DBA们的关键工作之一。

  然而,很多SQL Server系统的性能和扩展性并不理想,这通常是由糟糕的数据库设计,索引设计和SQL Server系统对工作负载的不适当配置造成的。因为任何大型SQL Server工程的开发都以实现功能为主要目的,至于性能和扩展性经常被当做一种事后才处理的东西。

  虽然对SQL Server系统的性能问题进行故障诊断困难重重,但是如果能用相对较少的时间投入,换取显着的性能提升,又何乐而不为呢。

  硬件性能瓶颈

  内存

  内存对SQL Server性能的影响胜过任何其他硬件。因此,对SQL Server系统的内存使用情况进行定期监视以确保内存的可用百分比高于20%是很有必要的。如果用户遭遇性能问题,同时可用内存百分比低于20%,那么此问题一定是内存分配不足导致的。这要求技术人员密切关注显示平均页面预期寿命的性能计数器,并确保平均页面预期寿命总是高于300秒(5分钟)。一旦放生少于此标准的情况,就说明要么是糟糕的索引设计导致了磁盘输入/输出(I/O)的增加,要么就是对内存的利用效率很低,或者是实际的内存不足。技术人员需要监视SQL Server系统上的分页率,并确保它们常规为1000页每秒。检查PerfMon object MSSQL Buffer Manager(性能监视对象MSSQL缓冲管理器)和Memory Performance Counters(内存性能计数器)。

  同样,还要监视计数器,即PerfMon object SQL Server Memory Manager Counters中的Memory Grants Pending.此计数器显示的是每秒钟等待工作负载分配的进程总数。一般来讲,小型OLTP事务不需要大内存分配。对一个OLTP事务来说,任何大于零的内存分配都说明SQL Server系统存在内存不足。

  解决内存瓶颈的途径之一是找出内存高耗进程,这可以确认诸如内存泄漏之类潜在的应用程序问题。你还可以通过检查查询优化性能以消耗更少的内存。另外一种方法就是给SQL Server增加更多的物理内存来扩展升级SQL Server环境。扩展升级通常是解决任何与内存相关的性能瓶颈的济世良方。

  磁盘I/O使用

  对比其他的硬件资源,存储输入/输出通常是SQL Server中最慢的系统资源。因此,监视存储系统以确定存储是否成为一个影响性能的瓶颈是十分重要的。如果是,那么下个步骤就是要调查是否能够优化存储系统的设计和配置以获得扩展性和高性能。检查Average Disk Sec/Read(秒均磁盘读取)和Average Disk Sec/Write (秒均磁盘写入)的PerfMon磁盘计数器。确保OLTP系统和更高决策支持系统的一个读或写的时间在理想情况下少于12毫秒。

  与内存一样,解决磁盘I/O性能瓶颈最简单的方法就是扩展升级SQL Server环境,即用更快的磁盘替换现有磁盘,可以更好地应对I/O负载和分配I/O负载到多个轴上。同时还要定期整理磁盘数据。

  CPU

  CPU性能瓶颈的发生有诸多原因。它们包括非理想的查询计划,应用程序或是数据库的设计缺陷,糟糕的SQL Server配置或是硬件资源的不足。技术人员可以对Processor Queue Length(处理器队列长度)的PerfMon operation system CPU(PerfMon操作系统CPU)和处理器计数器进行检查以验证正在等待CPU周期的线程数在八个以内。如果这一数字大于12,那就意味着CPU产生了性能问题。

  在确认了某个CPU瓶颈之后,便可以使用sys.dm_os_wait_stats动态管理视图(DMV)来确认对CPU来说排前十的性能最差的查询,如下所示。

SELECT TOP 10 (a.total_worker_time / a.execution_count) AS [Avg_CPU_Time]
  ,Convert(VARCHAR, Last_Execution_Time) AS [Last_Execution_Time]
  ,Total_Physical_Reads
  ,SUBSTRING(b.TEXT, a.statement_start_offset / 2, (
  CASE
  WHEN a.statement_end_offset = - 1
  THEN len(convert(NVARCHAR(max), b.TEXT)) * 2
  ELSE a.statement_end_offset
  END - a.statement_start_offset
  ) / 2) AS [Query_Text]
  ,dbname = Upper(db_name(b.dbid))
  ,b.objectid AS 'Object_ID', B.*
  FROM sys.dm_exec_query_stats a
  CROSS APPLY sys.dm_exec_SQL_text(a.SQL_handle) AS b
  ORDER BY [Avg_CPU_Time] DESC

  接着,你可以对这些查询和底层索引进行调优以解决CPU瓶颈。同时,对你的SQL Server进行配置以使用所有可用的CPU机器。你还可以通过添加额外的CPU或用更快的CPU升级一个新的服务器来扩展你的SQL Server系统。

  数据库设计问题

  高度规范化的数据库

  糟糕的数据库设计会导致数据库性能不足。例如,高度规范化的数据库是与复杂关系连接相关联的。这就造成了长时间执行查询对诸如CPU,内存,和磁盘I/O之类系统资源的浪费。显然,一个高度规范化的数据库会让SQL Server和数据库性能显着降低。编写高效查询的一般规则就是如果一个操作需要五个或者更多的表连接,就要对数据库进行重新设计。

  重复和未使用的索引

  索引是解决很多性能问题的杀手锏,但是在频繁更新的表上拥有过多的索引会招致额外开销,因为SQL Server在执行插入/更新/删除操作期间会执行额外的工作以保持索引处于最新状态。这就意味着在更新基于索引数量和复杂度的表中数据的时候,SQL Server数据库引擎需要更多的时间。同时,索引维护也会增加CPU和I/O使用,这会在一个密集写入的系统中对性能造成损害。因为任何重复和冗余的索引对系统资源来说毫无意义,所以需要将它们移除。

  在SQL Server中,我们可以使用sys.dm_db_index_usage_stats DMV来识别未使用的索引。DMV给出了一个索引是如何用于解析查询的相关统计数据。另外,你还可以执行Database Engine Tuning Advisor(数据库引擎调优顾问DTA)来识别未使用的索引。