SQL Server 2008 性能调优 session级别 wait event

简介: Investigating perfomance bottlenecks in  SQL Server 2008 by looking at wait events using the XE trace system Introduction.

Investigating perfomance bottlenecks in  SQL Server 2008 by looking at wait events using the XE trace system

Introduction.

In my previous articles  SQL Server Wait Events: Taking the Guesswork out of Performance Profiling,  and Taking the Guesswork out of SQL Server Performance Profiling Part 2, I introduced the concepts of performance analysis based on wait events.

In short, the idea behind this concept is to take the response time of a SQL statement (or a batch or a user session) and split it up into CPU time and Wait time..

Earlier versions of SQL Server only maintain wait time (aggregated) on the server level, or you can see the wait times and the wait reasons, and when they actually occur in views like sysprocesses orsys.dm_os_waiting_tasks. Starting with SQL Server 2005, the wait events are finally documented in the SQL Server BOL, and more and more background is provided in blogs, KB Articles, forums etc.

A wait event ‘happens’ when the SQL Server scheduler (implemented in the SQLOS) decides to suspend a running task.

This can be because a ‘long’ operation starts, such as disk,  network I/O, or  lock. It can also happen when the allotted time quantum that a task can be active on the CPU ends. At this moment this seems to be a hard-coded 4 ms. This is the means by which that the SQL Server scheduler makes sure that every task in SQL Server gets its turn running on the CPU. By carefully looking at the way the response time is build up, one can make intelligent decisions on where to look for possible optimizations, or capacity planning: For instance, if on your SQL Server box 90% of the total used (response) time consists of I/O waits and only 10% of the time is spend on the CPU, then adding CPU capacity or upgrading to faster CPUs is unlikely to have a very large impact on response times. The same is true for individual queries. If one query spends 90% of its time waiting for I/O, then speeding up the CPU will only impact the other 10% of the response time picture.

SQL Server 2008 introduces Extended Events (XE) a new event handling system. XE is a flexible and lightweight event trace system.

The SQL Server engine is instrumented with tracing code in many locations. It is possible to trace ‘traditional’ events as existed in older SQL Trace versions, events like ‘RPC:Completed’. ‘sp_completed’, ‘lock timeout’ etc.

An exciting new tracing feature, is the means by which one can trace information about SQL Server OS (SQLOS) wait events

Each event contains a set of interesting columns that will be logged to a ‘target’. In this example, we have chosen a file. Next to the ‘default’ set of columns for an event, extra information can be logged as well. This is done by defining ‘actions’ on a traced event. Below is an example of standard columns that are logged for the event‘wait_info’ in the package ‘sqlos’, and for the event, ‘sql_statement_completed’ in the sqlserver package, which will also be used in the example:

name                         column_id       object_name           

--------------------         -----------     -----------------------             

wait_type                    0                wait_info        

opcode                       1                wait_info 

duration                     2                wait_info 

max_duration                 3                wait_info 

total_duration               4                wait_info 

signal_duration              5                wait_info 

completed_count              6                wait_info

source_database_id           0                sql_statement_completed

object_id                    1                sql_statement_completed

object_type                  2                sql_statement_completed

cpu                          3                sql_statement_completed

duration                     4                sql_statement_completed

reads                        5                sql_statement_completed

writes                       6                sql_statement_completed

Next is an example on how to setup wait event tracing and collecting information from an ‘asynchronous file target’.  Only specific events are collected for session_id=53.

First we create the ‘event session’, and start it.

After this, we can run an example query from a session with session_id=53, a count(*) query was run on a 1 million row (unindexed) table.

Example 1:

 

create event session test1

on server

add event sqlserver.sql_statement_starting

(action

            (sqlserver.session_id, package0.collect_system_time,

package0.collect_cpu_cycle_time,sqlserver.sql_text,

sqlserver.plan_handle, sqlos.task_address, sqlos.worker_address)

            where sqlserver.session_id = 53),

add event sqlserver.sql_statement_completed

(action

(sqlserver.session_id, package0.collect_system_time,package0.collect_cpu_cycle_time, sqlserver.sql_text,

sqlserver.plan_handle, sqlos.task_address, sqlos.worker_address)

      where sqlserver.session_id = 53),

add event sqlos.wait_info

            (action

(sqlserver.session_id,  package0.collect_system_time,package0.collect_cpu_cycle_time, sqlos.task_address, sqlos.worker_address)

       where sqlserver.session_id = 53)

--

--          async file, read with: sys.fn_xe_file_target_read_file

--

 ADD TARGET package0.asynchronous_file_target

(SET filename = N'C:\temp\wait.etx', metadatafile = N'C:\temp\wait.mta',

                        max_file_size = 50, max_rollover_files = 10)

            WITH (max_dispatch_latency = 2 seconds)

go

alter event session test1 on server state = start

go

Example 2:

The next example shows how to collect the trace information from the trace files for further processing. As you can see from the example, the files is read ‘through’ a virtual function, ‘sys.fn_xe_file_target_read_file‘, and the rows are returned in XML form.

The insert into the xTable counted 4938 rows. For the next summary I only collected the ‘wait_info’ ‘end’ events (1560 rows) and the ‘sql_statement_completed’ event (1 row):

drop table xTable

CREATE TABLE xTable

    (

      xTable_ID INT IDENTITY

                    PRIMARY KEY,

      xCol XML

    ) ;

 

INSERT  INTO xTable ( xCol )

select cast(event_data as xml) waitinfo from sys.fn_xe_file_target_read_file

('c:\temp\wait_*.etx',

'c:\temp\wait_*.mta',

null,null)

Now in order to extract the CPU and Wait information and match it with the total response time, we run the following queries:

SELECT 

-- for some reason wait type name is not logged with synch target. bug?

(select map_value from sys.dm_xe_map_values

    where name = 'wait_types'

        and map_key = xCol.value('(event/data/value)[1]', 'int')

)AS wtype,

     xCol.value('(event/data/value)[3]', 'int')  --wait time

                                    AS tottime,

     xCol.value('(event/data/value)[6]', 'int') --sig wait time

                                    AS sigtime

     into #mywaits   

FROM    xTable

where xCol.value('(/event/@name)[1]', 'varchar(30)') = 'wait_info'     

 and xCol.value('(event/data/value)[2]', 'int') = 1 --opcode end         

 

select  wtype,

        count(*) as wcount,

        sum(tottime) as total_time,

        sum(sigtime) as signal_time

        from #mywaits group by wtype

go

-- stmt completed:

 

SELECT 

                        xCol.value('(event/data/value)[4]', 'int')

                                    AS cputime,

                        xCol.value('(event/data/value)[5]', 'int')

                                    AS duration,

                        xCol.value('(event/action/value)[4]', 'varchar(MAX)')

                                    AS sql_text

into #mysql

FROM    [xTable]

where xCol.value('(/event/@name)[1]', 'varchar(30)') ='sql_statement_completed'    

select  sql_text,

        count(*) as count,

        SUM(cputime) as cputime,

        SUM(duration) as duration from #mysql group by sql_text

go

drop table #mywaits

drop table #mysql

This is the result of the above queries:

   wtype                       wcount         total_time    signal_time   

--------------------------  -----------    -----------   -----------   

PWAIT_SOS_SCHEDULER_YIELD   20             45            0             

PWAIT_SLEEP_TASK            1              10            0             

PWAIT_PAGEIOLATCH_SH        1539           59163         674           

                                                                            

 (1 row(s) affected)                                                           

sql_text                    count      cputime   duration      

-------------------------   --------   --------  -----------   

select COUNT(*) from t1m    1          1892      61560364      

                                                                             

So what we can see here is that the statement response time (duration) was 6156 ms (apparently, the sqlserver.sql_statement_completed.duration is measured in microseconds)

The CPU time used was 1892 ms and the wait time for the three different wait events was 45+10+59163 ms = 59218 ms. Including the measured signal_time (the time between the end of the actual wait and the resumption of work) this nicely adds up to the total duration of the query.

For more information on the specific wait events, search the SQL Server BOL for the sys.dm_os_wait_stats view. All wait events are documented here.

It is also possible to look at each individual wait event. This can be useful to detect skew in wait durations for example. If you detect that certain I/O operations take longer than others, it might be interesting to add other XEvents to trace. Events like ‘file_read_completed’ will show which file was read and which offset within the file. The event ‘physical_page_read’, can tell which page for which file. These events can help detecting if you might be reading from slow disks or doing random I/O while you were expecting to do sequential I/Os.

-- first: sql_statement_starting

SELECT  xTable_ID,

                        xCol.value('(event/action/value)[1]', 'int')

                                    AS session_id,

                        xCol.value('(/event/@timestamp)[1]', 'varchar(24)')

                                    AS EventTime,

                        xCol.value('(/event/@name)[1]', 'varchar(30)')

                                    AS EventType,

                        xCol.value('(event/action/value)[2]', 'varchar(30)')

                                    AS system_time,

                        xCol.value('(event/action/value)[3]', 'varchar(30)')

                                    AS cpu_cycle_time,

                        xCol.value('(event/data/value)[5]', 'varchar(30)')

                                    AS data1,

                        xCol.value('(event/data/value)[6]', 'varchar(30)')

                                    AS data2,

                        xCol.value('(event/action/value)[4]', 'varchar(MAX)')

                                    AS sql_text

FROM    [xTable]

where xCol.value('(/event/@name)[1]', 'varchar(30)') = 'sql_statement_starting'

union    --now collect: statement_completed                    

SELECT  xTable_ID,

                        xCol.value('(event/action/value)[1]', 'int')

                                    AS session_id,

                        xCol.value('(/event/@timestamp)[1]', 'varchar(24)')

                                    AS EventTime,

                        xCol.value('(/event/@name)[1]', 'varchar(30)')

                                    AS EventType,

                        xCol.value('(event/action/value)[2]', 'varchar(30)')

                                    AS system_time,

                        xCol.value('(event/action/value)[3]', 'varchar(30)')

                                    AS cpu_cycle_time,

                        xCol.value('(event/data/value)[4]', 'varchar(30)')

                                    AS data1,

                        xCol.value('(event/data/value)[5]', 'varchar(30)')

                                    AS data2,

                        xCol.value('(event/action/value)[4]', 'varchar(MAX)')

                                    AS sql_text

FROM    [xTable]

where xCol.value('(/event/@name)[1]', 'varchar(30)') = 'sql_statement_completed'

union

SELECT  xTable_ID,

                        xCol.value('(event/action/value)[1]', 'int')

                                    AS session_id,

                        xCol.value('(/event/@timestamp)[1]', 'varchar(24)')

                                    AS EventTime,

-- for some reason wait type name is not logged with synch target. bug?

                         (select map_value from sys.dm_xe_map_values

                            where name = 'wait_types'

                            and map_key =  xCol.value('(event/data/value)[1]','int')

                          as Event_name,

                        xCol.value('(event/action/value)[2]', 'varchar(30)')

                                    AS system_time,

                        xCol.value('(event/action/value)[3]', 'varchar(30)')

                                    AS cpu_cycle_time,

xCol.value('(event/data/value)[3]', 'varchar(30)')  --wait time

                                    AS data1,

xCol.value('(event/data/value)[6]', 'varchar(30)') --sig wait time

                                    AS data2,

                        ''

                                    AS sql_text

                       

FROM    [xTable]

where xCol.value('(/event/@name)[1]', 'varchar(30)') = 'wait_info'     

 and xCol.value('(event/data/value)[2]', 'int') = 1 -- opcode end        

 

 

This article, submitted in May, was originally scheduled for publication as part of Simple-Talk's celebration of the launch of SQL Server 2008 next month, but has been brought forward in view of the current interest in the subject

 
目录
相关文章
|
SQL 运维 监控
SQL查询太慢?实战讲解YashanDB SQL调优思路
本文是Meetup第十期“调优实战专场”的第二篇技术文章,上一篇《高效查询秘诀,解码YashanDB优化器分组查询优化手段》中,我们揭秘了YashanDB分组查询优化秘诀,本文将通过一个案例,助你快速上手YashanDB慢日志功能,精准定位“慢SQL”后进行优化。
|
10月前
|
SQL 关系型数据库 MySQL
为什么这些 SQL 语句逻辑相同,性能却差异巨大?
我是小假 期待与你的下一次相遇 ~
371 0
|
SQL 关系型数据库 PostgreSQL
CTE vs 子查询:深入拆解PostgreSQL复杂SQL的隐藏性能差异
本文深入探讨了PostgreSQL中CTE(公共表表达式)与子查询的选择对SQL性能的影响。通过分析两者底层机制,揭示CTE的物化特性及子查询的优化融合优势,并结合多场景案例对比执行效率。最终给出决策指南,帮助开发者根据数据量、引用次数和复杂度选择最优方案,同时提供高级优化技巧和版本演进建议,助力SQL性能调优。
1490 1
|
SQL 关系型数据库 MySQL
大数据新视界--大数据大厂之MySQL数据库课程设计:MySQL 数据库 SQL 语句调优方法详解(2-1)
本文深入介绍 MySQL 数据库 SQL 语句调优方法。涵盖分析查询执行计划,如使用 EXPLAIN 命令及理解关键指标;优化查询语句结构,包括避免子查询、减少函数使用、合理用索引列及避免 “OR”。还介绍了索引类型知识,如 B 树索引、哈希索引等。结合与 MySQL 数据库课程设计相关文章,强调 SQL 语句调优重要性。为提升数据库性能提供实用方法,适合数据库管理员和开发人员。
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
关系型数据库 MySQL 大数据
大数据新视界--大数据大厂之MySQL 数据库课程设计:MySQL 数据库 SQL 语句调优的进阶策略与实际案例(2-2)
本文延续前篇,深入探讨 MySQL 数据库 SQL 语句调优进阶策略。包括优化索引使用,介绍多种索引类型及避免索引失效等;调整数据库参数,如缓冲池、连接数和日志参数;还有分区表、垂直拆分等其他优化方法。通过实际案例分析展示调优效果。回顾与数据库课程设计相关文章,强调全面认识 MySQL 数据库重要性。为读者提供综合调优指导,确保数据库高效运行。
|
SQL 关系型数据库 OLAP
云原生数据仓库AnalyticDB PostgreSQL同一个SQL可以实现向量索引、全文索引GIN、普通索引BTREE混合查询,简化业务实现逻辑、提升查询性能
本文档介绍了如何在AnalyticDB for PostgreSQL中创建表、向量索引及混合检索的实现步骤。主要内容包括:创建`articles`表并设置向量存储格式,创建ANN向量索引,为表增加`username`和`time`列,建立BTREE索引和GIN全文检索索引,并展示了查询结果。参考文档提供了详细的SQL语句和配置说明。
685 2
|
SQL Oracle 关系型数据库
如何在 Oracle 中配置和使用 SQL Profiles 来优化查询性能?
在 Oracle 数据库中,SQL Profiles 是优化查询性能的工具,通过提供额外统计信息帮助生成更有效的执行计划。配置和使用步骤包括:1. 启用自动 SQL 调优;2. 手动创建 SQL Profile,涉及收集、执行调优任务、查看报告及应用建议;3. 验证效果;4. 使用 `DBA_SQL_PROFILES` 视图管理 Profile。
|
SQL 存储 缓存
如何优化SQL查询性能?
【10月更文挑战第28天】如何优化SQL查询性能?
1072 10
|
SQL IDE 数据库连接
IntelliJ IDEA处理大文件SQL:性能优势解析
在数据库开发和管理工作中,执行大型SQL文件是一个常见的任务。传统的数据库管理工具如Navicat在处理大型SQL文件时可能会遇到性能瓶颈。而IntelliJ IDEA,作为一个强大的集成开发环境,提供了一些高级功能,使其在执行大文件SQL时表现出色。本文将探讨IntelliJ IDEA在处理大文件SQL时的性能优势,并与Navicat进行比较。
408 4