SQL Server 2005性能排错白皮书(Part 2)---From MS Customer Support Service部门

检测

内部查询的并行问题可以通过下列方法检测。

系统监视器(Perfmon)

考虑SQL Server:SQL Statistics – Batch Requests/sec 计数器,并查看SQL Server联机丛书中的“SQL Statistics Object”获取更多信息。因为在考虑使用并行计划前,查询必须评估开销超过为并行配置设置的开销阀值(默认被设置为5),服务器每秒处理的批小于运行在并行计划中的批。运行很多并行查询的服务器一般配置为较小的每秒批请求数(例如,小于100的值)。

DMVs

在运行的服务器上,你可以使用下列查询确认在给定会话中是否可以并行运行任何活动的请求。

select r.session_id,r.request_id,max(isnull(exec_context_id, 0)) as number_of_workers,r.sql_handle,r.statement_start_offset,r.statement_end_offset,r.plan_handlefrom

sys.dm_exec_requests rjoin sys.dm_os_tasks t on r.session_id = t.session_idjoin sys.dm_exec_sessions s on r.session_id = s.session_idwhere s.is_user_process = 0x1group by

r.session_id, r.request_id, r.sql_handle, r.plan_handle, r.statement_start_offset, r.statement_end_offsethaving max(isnull(exec_context_id, 0)) > 0

通过这些信息,查询的文本可以通过使用sys.dm_exec_sql_text轻松获取,而查询计划可以使用sys.dm_exec_cached_plan获取。你也可以搜索符合运行在并行的计划。这可以通过搜索缓存的计划来查看如果关系操作符有Parrallel属性为非零的值。这些计划也许可以不运行在平行中,但是他们如果系统不忙,他们也适合这样做。

---- Find query plans that may run in parallel--select p.*, q.*,cp.plan_handlefrom sys.dm_exec_cached_plans cpcross apply sys.dm_exec_query_plan(cp.plan_handle) pcross apply sys.dm_exec_sql_text(cp.plan_handle) as qwhere cp.cacheobjtype = 'Compiled Plan' andp.query_plan.value('declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";max(//p:RelOp/@Parallel)', 'float') > 0

一般来说,查询的持续时间长于CPU时间总量,因为一些时间花费在等待资源上例如锁或物理I/O。查询使用CPU时间长于持续时间的唯一场景是当查询运行在并行计划例如多线程并发使用CPU。注意并不是所有并行查询将证明这种行为(CPU时间大于持续时间)。

select qs.sql_handle, qs.statement_start_offset, qs.statement_end_offset, q.dbid,q.objectid,q.number,q.encrypted,q.textfrom sys.dm_exec_query_stats qscross apply

sys.dm_exec_sql_text(qs.plan_handle) as qwhere qs.total_worker_time > qs.total_elapsed_timeSQL TraceLook for the following signs of parallel queries, which could be either statements or batches that have CPU time greater than the duration.select EventClass, TextData from ::fn_trace_gettable('c:\temp\high_cpu_trace.trc', default)where EventClass in (10, 12) -- RPC:Completed, SQL:BatchCompletedand CPU > Duration/1000 -- CPU is in milliseconds, Duration in microsecondsOr can be Showplans (un-encoded) that have Parallelism operators in themselect EventClass, TextData from ::fn_trace_gettable('c:\temp\high_cpu_trace.trc', default)where TextData LIKE '%Parallelism%'

解决

任何运行在并行计划的查询被查询优化器认为是成本昂贵的,并会超过并行阀值,默认为5(粗略的是在涉及的机器上5秒执行一次)。任何通过上述方法确认的查询都是以后要调节的候选者。

◆使用Database Engine Tuning Advisor查看是否任何索引改变,改变索引视图或分区改变能减少查询的开销
◆检查实际值和评估集的重要不同因为评估集在评估查询开销中是重要因素。如果找到重要的不同:

如果auto create statistics数据库设置被禁用,确认在Showplan输出的Warnings列中没有MISSING STATS项。尝试在关闭评估的表上运行UPDATE STATISTICS。验证查询没有使用优化器无法精确评估的查询构造,例如多语句表值函数或CLR函数,表值或Transact-SQL变量比较(参数比较是可以的)。

◆评估是否可以使用不同的Transact-SQL语句或表达式将查询写的更有效率

拙劣游标使用

SQL Server 2005之前的SQL Server 版本仅支持在每个连接上有单个活动的操作。一个查询正在执行或有了结果等待发送到客户端时将被认为是活动的。在一些情形中,客户端应用程序也许需要从结果中读取并向SQL Server提交其他基于刚刚从结果集中读取的行的查询。这在默认的结果集中是不能实现的,因为还有其他等待的结果。一般的解决方法是改变连接属性是用服务器端游标。

当使用服务器端游标,数据库客户端软件(OLE DB提供者或ODBC驱动)显然会封装客户端请求在特殊的扩展存储过程中,例如sp_cursoropen,sp_cursorfetch等等。这提到了API游标(而不是TSQL游标)。当用户执行查询,查询文本通过sp_cursoropen被发送到服务器,请求读取从sp_cursorfetch指示服务器进发送某些数量的行。通过控制获取行的数量,可以为ODBC驱动或OLE DB提供者缓存行。这阻止发生服务器等待客户端都区所有发送的行的情形。因此,服务器可以在这个连接上接受新的请求。

一次性打开游标并获取1行(或少量行)的应用程序能被网络延时的网络瓶颈影响,特别是在广域网(WAN)。在有快速网络并有不同用户连接时,处理很多游标请求的开销变得更重要。因为开销来自于游标位置的变化来适应在结果集上的位置改变,预请求的处理开销,类似的处理,服务器处理1个请求返回100行必处理100不同请求相同的100行但是每次1行更有效率。

检测

你可以使用下列方法为拙劣游标使用排错。

系统监视器(Perfmon)

通过考虑SQL Server:Cursor Manager By Type – Cursor Requests/Sec计数器,你可以通过这个性能计数器知道有多少游标在系统中使用。系统还有很高的CPU利用率,因为小量的读取通常会有每秒数百个游标请求。这里没有特殊的计数器告诉你关于获取的缓存大小。

DMVs

接下来的查询可以用于测定使用API游标(不是TSQL游标)连接获取一行使用的缓存大小。它对于大的获取缓存更有效,例如100行。select cur.* from sys.dm_exec_connections concross apply sys.dm_exec_cursors(con.session_id) as curwherecur.fetch_buffer_size = 1 and cur.properties LIKE 'API%' -- API cursor (TSQL cursors always have fetch buffer of 1)


SQL 跟踪

使用包括RPC:Completed事件类的跟踪用于搜索sp_cursorfetch语句。第4个参数的值是通过获取返回的行数。请求返回的最大行数是被指定为与RPC:Starting事件类关联的参数

解决

◆确定游标是完成操作的最佳方法或是否基于集合这种更有效的操作是可行的。
◆当连接到SQL Server 2005,考虑使用多活动结果集(MARS)
◆参考你使用的API文档决定如何指定游标的获取缓存大小:

ODBC - SQL_ATTR_ROW_ARRAY_SIZE
OLE DB – IRowset::GetNextRows or IRowsetLocate::GetRowsAt

内存瓶颈

这部分给出了低缓存的条件和对不同内存错误诊断方法,可能的原因和排错方法。

背景

引用不同的内存资源通过使用简单的术语内存。但是却有一些内存资源类型,对于理解和区分特殊的内存资源这是很重要的。虚拟地址空间和物理内存在Microsoft Windows®,每个进程都有自己的虚拟地址空间(VAS)。进程可用所有虚拟地址有VAS的大小决定。VAS的大小依赖于架构(32位或64位)和操作系统。在排错的上下文中,理解虚拟地址空间使用内存资源,了解应用程序可以超出VAS即使在64位平台只要物理地址可能一直可用,这些很重要。更多有关于虚拟地址空间,请查看SQL Server联机丛书中“Process Address Space”和MSDN中的Virtual Address Space。

Windows地址扩展和SQL Server

Windows地址扩展(AWE)是允许32位应用程序跨越32位地址限制操作内存的API。AWE机制技术上不需要64位平台。然而它出现了。内存页通过AWE机制涉及在64位平台上的锁定页。

在32位和64位平台上,内存通过AWE机制分配不能分页出界。这可以有益于应用程序(这是在64位平台上使用AWE机制的原因)。这也影响了系统和其他应用程序可用RAM总数,这可能是有害的影响。因为这个原因为了使用AWE,Lock Pages in Memory权利必须分配该运行SQL Server的账号。从排错的角度来看,要点是SQL Server缓存池使用AWE映射内存;然而,只有数据库(hash过的)页面可以利用AWE分配内存。通过AWE机制内存分配将不会在任务管理器或在Process: Private Bytes性能计数器中看到。你需要使用SQL Server特殊的计数器或动态管理视图来获取这些信息。

更多关于AWE映射内存的信息,请在SQL Server联机丛书中查看“Managing memory for large databases” 和 “Memory Architecture”以及MSDN中的Large Memory Support下列表汇总了不同SQL Server 2005支持的最大内存(注意特殊的SQL Server版本或Windows可以有不同支持内存的限制)

内存压力

内存压力表示当可用内存数量受到限制。识别SQL Server何时运行在内存压力下将帮助你排除内存相关的问题。SQL Server依赖于不同类型的内存压力特征也不一样。下表汇总了内存压力类型,和他们潜在的原因。在所有的情况下,你可以更多的会见到超时或显示的内存不足错误消息。表 2

压力
   外部
   内部
物理
   物理内存(RAM)运行值低。这导致系统整理当前运行的工具集,导致整体性能下降。

 SQL Server监测到这种条件,依赖于配置,可以减少缓存池的目的提交并开始清理内部缓存。
 SQL Server检测内部较高的内存消耗,导致在不同内部组件间的内存重新分配。

 内部内存压力可以导致:

    导致外部内存压力(SQL Server设置地的内存使用能力)。

    改变内存设置(例如‘max server memory’)。

    改变内部组件的内存分布(导致预留的高百分比并从缓存池中获取页)。
 
虚拟的
 在系统页面文件运行在较低值。这样可以导致系统分配内存失败。不能扩展当前的内存分配。这可以导致着整个系统响应很慢或者可能导致系统关机。在VAS运行值低,导致分页(很多VAS可用,但是被分为小块)与/或消耗(直接分配,DLL加载到SQL VAS,大量的线程)。
SQL Server检测到这种条件并可以释放VAS中保留的区域,减少缓存池提交的目标并开始收缩缓存。Windows有通知的机制  如果物理内存运行在过高或过低的情况下。SQL Server在他的内存管理决策中使用这种机制。一般排错的步骤显示在表3中。

表 3

压力
   内部
   外部
物理
   找到主要的系统内存消耗组件。

   尝试消除消耗(如果可能)。

   检查适当的系统RAM和考虑添加额外RAM(通常需要更仔细研究)
   识别SQL Server内主要的内存消耗

   确认系统配置。

   进一步操作依赖于研究;检查负载;可能出现的设计问题;其他的资源瓶颈。
 
虚拟
   增加交换文件大小。

   检查主要物理内存的使用和外部物理内存压力调用步骤。
   外部物理内存压力调用步骤。
 
工具

下列工具和资源可以用于排错。

◆内存相关的DMVs
◆DBCC MEMORYSTATUS 命令
◆性能计数器: 性能监视器或SQL Server指定对象的DMV
◆任务管理器
◆事件查看器: 应用程序日志和系统日志

检测内存压力

内存压力自身不会预示问题。内存压力是需要的,但时不是为服务器以后遇到内存错误的充分条件。在内存压力下工作将被任务是服务器的正常操作。然而内存压力的征兆可以于是服务器运行已经接近设计容量并且潜在存在内存不足的错误。在正常运行情况下,这些信息将作为基线决定以后内存不足的原因。

外部物理内存压力

打开人物管理器的性能视图,检查Physical Memory节的Available项的值。如果可用内存总数很低,这表现了有外部内存压力。这个准确值依赖于很多因素,然而你可以在当这个值降低到50-100MB开始查找问题。当这个总数小于10MB时,外部内存压力将表现得很明显。相同信息也可以使用在系统监视器中的Memory: Available Bytes计数器获取。

如果存在外部内存压力并且你看到了内存相关的错误,你需要确认在系统中主要的内存消耗者。为了这个,考虑Process: Working Set性能计数器或在任务管理器中Process栏中的Mem Usage列,找到最大的内存消耗者。

系统中所有使用的物理内存可以通过汇总下列计数器获取。

◆Process 对象,每个进程的 Working Set计数器
◆Memory 对象
◆系统的Cache Bytes计数器
◆未分页池的Pool Nonpaged Bytes 计数器
◆Available Bytes (等于任务管理其中的Available 值)

如果没有外部压力,Process: Private Bytes计数器或在任务管理器中虚拟内存将接近工作集的大小(Process: Working Set或任务管理器中的Mem Usage),意味着我们没有内存用于分页了。

注意任务管理器中的Mem Usage列和相应的性能计数器不能计算通过AWE分配的内存。这样如果使用AWE,信息将是不完整的。这种情况下,你需要考虑在SQL Server内分配的内存来获取完整的信息。

你可以使用sys.dm_os_memory_clerks DMV找到SQL Server通过AWE机制分配了多少内存,如下所示。

select sum(awe_allocated_kb) / 1024 as [AWE allocated, Mb] from sys.dm_os_memory_clerks

注意在SQL Server中,只有当前缓存池(’MEMORYCLERK_SQLBUFFERPOOL’类型)使用这种机制并且只能是在使用AWE功能时。通过识别和除去主要物理内存使用者(如果有可能)和/或 通过添加更多的内存的方法解除外部内存压力一般可以解决与此相关的内存问题。

外部虚拟内存压力

你需要确定是否页面文件为当前内存的分配能提供足够的空间。为了检查,可以打开任务管理器中的性能视图,并检查Commit Charge节。如果Total接近于Limit则说明可以被提交的最大数量内存没有扩展页面的空间。注意任务管理器中的Commit Charge Total指出潜在使用的页面文件,而不是实际使用值。实际使用的页面文件将增加物理内存压力。

同样可以通过下列技术起获取相关信息:Memory: Commit Limit, Paging File: %Usage, Paging File: %Usage Peak。你可以通过每个进程的Process: Working Set减去Process Private Bytes计数器来评估内存总数。如果Paging File: %Usage Peak(或Peak Commit Charge)很高,检查系统日志中是否有指出页面文件增长或通知“running low on virtual memory”的信息。你可能需要增加你的页面文件大小。High Paging File: %Usage指出物理内存超过要提交的值并也要考虑外部物理内存压力(大量的内存需求,没有足够的RAM)。

内部物理内存压力

内部内存压力来自于SQL Server自身,应首先通过检查在缓存分布中的异常来考虑在SQL Server内存分布。通常在SQL Server中缓存会占用最多提交的内存。为了确定在缓存池中的内存总数,我们可以使用DBCC MEMROYSTATUS命令。在Buffer Counts节,可以找到Target值。下列输出显示了在服务器达到正常负载时DBCC MEMORYSTATUS的结果

Buffer Counts                  Buffers------------------------------ --------------------Committed                      201120Target                         201120Hashed                         166517Reserved Potential     

       143388Stolen Potential               173556External Reservation           0Min Free                       256Visible                        201120Available Paging File          460640
 
Target是SQL Server计算出它在不导致分页时可以提交的8-KB每页的页数。

Target是被定期的重新计算的来反映内存的低或高。在常规服务负载下target页面过低可能预示出现了外部内存压力。

如果SQL Server占用了大量的内存(通过Process: Private Bytes或 任务管理器中Mem Usage 列显示),请查看是否Target的数值。注意,如果启用AWE,你还要从sys.dm_of_memory_clerks或DBCC MEMORYSTATUS输出计算AWE分配的总量。

考虑上面的示例(没有启用AWE),Target*8KB=1.53GB,而服务器的Process: Private Bytes大约是1.62GB或缓存池用SQL Server占用了94%的内存。注意,如果服务器没有过载,Target是应该超过Process: Private Bytes性能计数器报告的数量。

如果Target过低,但是服务器的Process: Private Bytes或 任务管理器中Mem Usage 值很高,我们也许要面对从缓存池外使用内存的组件带来的内部内存压力。被加载到SQL Server进程中的组件,例如COM对象,连接服务器,扩展存储过程,SQLCLR或其他会从缓存池外占用内存。如果不使用SQL Server内存接口,将没有方法跟踪组件在缓存池外占用的内存。

适用于SQL Server内存管理机制的组件使用在缓存池中分配很少的内存。如果分配的大于8KB,这些组将将通过多页分配器借口使用缓存池外的内存。下列方法可以快速检查通过多业分配器接口占用的内存数量。

-- amount of mem allocated though multipage allocator interfaceselect sum(multi_pages_kb) from sys.dm_os_memory_clerks

你可以这样获得通过多页分配器分发内存的详细信息:

select type, sum(multi_pages_kb) from sys.dm_os_memory_clerks where multi_pages_kb != 0 group by typetype                                       ------------------------------------------ ---------

MEMORYCLERK_SQLSTORENG                     56MEMORYCLERK_SQLOPTIMIZER                   48MEMORYCLERK_SQLGENERAL                    

2176MEMORYCLERK_SQLBUFFERPOOL                  536MEMORYCLERK_SOSNODE                        16288CACHESTORE_STACKFRAMES                    

16MEMORYCLERK_SQLSERVICEBROKER               192MEMORYCLERK_SNI                            32


如果通过多页分配器分发了过大的内存( 100-200MB或更多),应该做进一步的研究。如果你看到了通过多页分配器 分发的大量内存,检查服务器的配置并尝试使用之前或后续的查询确定哪个组件占用的最多的内存。如果Target值低,但是在百分比上它占用了最多的内存,请在前面部分中查找描述外部内存压力的部分(External Physical Memory Pressure),或查看服务器内存配置参数。

如果你设置了max server memory 和/或min server memory,你应该用这些值和Target值进行比较。max server memory选项限制了在缓存池中占用内存的最大值,而服务器还可以占用其他的部分。min server memory选项告诉服务器当小于该值时不能释放缓存池的内存。如果Target小于min server memory设置并且服务器没有过载,这可能预示服务器遇到了外部内存压力并且不能获得这个设置大小的内存。它也可能预示着从内部组件的内存压力,就像上面描述的那样。Target 数值不能超过max server memory选项的设置。

首先,检查从DBCC MEMORYSTATUS输出中Stolen页面数量

Buffer Distribution            Buffers------------------------------ -----------Stolen                         32871Free                           17845Cached                         1513Database (clean)              

148864Database (dirty)               259I/O                            0Latched                        0

相对于Stolen和Target页面的高百分比(>75-80%)预示着内部内存压力。更多关于服务器组件内存分配的信息可以使用sys.dm_of_memory_clerks DMV获取。

-- amount of memory consumed by components outside the Buffer pool -- note that we exclude single_pages_kb as they come from BPool-- BPool is accounted for by the next queryselectsum(multi_pages_kb + virtual_memory_committed_kb+ shared_memory_committed_kb) as [Overall used w/o BPool, Kb]from sys.dm_os_memory_clerks where type <> 'MEMORYCLERK_SQLBUFFERPOOL'-- amount of memory consumed by BPool-- note that currenlty only BPool uses AWEselectsum(multi_pages_kb + virtual_memory_committed_kb+ shared_memory_committed_kb+ awe_allocated_kb) as [Used by BPool with AWE, Kb]from sys.dm_os_memory_clerks where type = 'MEMORYCLERK_SQLBUFFERPOOL'

你可能感兴趣的:(sql server 2005)