SQL Server优化入门系列(一)——快速定位阻塞SQL

俊达3年前技术文章1243

引言

我们在运维数据库的时候,经常会面对这样的问题:

  • 数据库现在运行得怎么样

  • 有哪些会话在执行,当前状态是什么,在执行什么SQL

  • 哪些会话被阻塞,阻塞原因是什么

  • 会话是从哪些IP连接过来的,使用了什么账号


通过这篇文章介绍的方法,我们可以快速找到SQL Server中正在运行的SQL,以及被阻塞的会话。


连接和请求

我们可以通过SQL Server提供的一系列DMV来解答上面这些问题。

要用好这些DMV,需要我们对SQL Server的基本概念和运行机制有一些基本的了解。


客户端执行一个SQL,大致可分为几个步骤:

1、建立连接

2、将请求(SQL)发送到服务端


服务端收到客户端发送的请求后,需要:

1、解析和优化SQL

2、请任务(Task)分配到Worker执行

3、将结果返回给客户端



下面的表格介绍了一个请求执行过程中,涉及到的核心的概念和相关的DMV:

概念

描述

相关DMV

连接

(Connection)

客户端到服务端的物理通道。

一般是TCP连接。

sys.dm_exec_connections

  • 通过session_id或most_recent_session_id关联 sys.dm_exec_session和sys.dm_exec_request表。

  • 通过most_recent_sql_handleg关联sys.dm_exec_sql_text,获取sql文本

会话

(Session)

用户请求都会通过一个会话发送。

会话会绑定到一个连接上。

sys.dm_exec_sessions

  • 通过session_id关联sys.dm_exec_requests表

  • 通过session_id关联sys.dm_exec_connections表的session_id或most_recent_session_id

请求

(Request)

一个请求可以简单理解为发送给服务器的任务(一个SQL语句、一个Batch)。

SQL Server接收到用户请求后,会生成对应的Task,分配给worker执行。

sys.dm_exec_requests

当前系统中运行的requests。

请求执行完成后,从该dmv中就查不到相关信息了。

  • 通过sql_handle关联sys.dm_exec_sql_text,结合statement_start_offset,statement_end_offset获取请求的SQL语句

  • 通过plan_handle关联sys.dm_exec_text_query_plan获取执行计划

  • 通过task_address关联sys.dm_os_tasks,sys.dm_os_waiting_tasks获取task相关信息

  • 通过session_id关联sys.dm_exec_sessions、sys.dm_exec_connections表,获取发起任务的会话和连接信息

  • 通过blocking_session_id关联

sys.dm_exec_sessions获取阻塞当前会话的session。如果引起阻塞的SQL还在执行,可以关联request、task表获取SQL语句。如果引起引起阻塞的SQL已经执行完成,则只能关联到connection表,获取会话最后执行的SQL。

任务

(task)

用户发起的请求,服务端以task的方式运行。task会分配到某个worker执行,在task执行完成之前,worker不会执行其他task。

并行查询中,一个父task会产生多个子task。

task状态:

  • PENDING: Waiting for a worker thread.

  • RUNNABLE: Runnable, but waiting to receive a quantum.

  • RUNNING: Currently running on the scheduler.

  • SUSPENDED: Has a worker, but is waiting for an event.

  • DONE: Completed.

  • SPINLOOP: Stuck in a spinlock.

sys.dm_os_tasks,

  • 通过task_address字段关联sys.dm_exec_requests,获取请求相关信息(如SQL语句)

  • 通过session_id关联sys.dm_exec_sessions、sys.dm_exec_connections表,获取发起任务的会话和连接信息

  • 通过parent_task_address关联sys.dm_os_tasks表,获取父task(如果非空)

  • 通过worker_address关联sys.dm_os_workers表,获取worker信息

sys.dm_os_waiting_tasks

  • blocking_session_id:阻塞会话ID

  • blocking_task_address: 阻塞task地址(若存在)

  • wait_duration_ms

  • wait_type

  • resource_address

Worker

worker线程(thread)或fiber,用于执行task

sys.dm_os_workers

  • tasks_processed_count:处理的任务数

  • pending_io_count:完成的io请求数

  • task_address: 关联sys.dm_os_tasks表

  • last_wait_type

Scheduler

woker会分配到某个scheduler执行。scheduler相当于逻辑CPU。


sys.dm_os_schedulers

  • load_factor: scheduler负载情况。

  • current_tasks_count:当前任务数

  • runnable_tasks_count:等待CPU的任务数

  • current_workers_count:当前worker数

  • active_workers_count:活动worker数

  • pending_disk_io_count:待完成的IO请求数

    会话相关查询

    查询所有会话连接和执行的SQL

    通过如下SQL可以查询SQL Server实例当前正在运行的SQL


    select 
    	a.client_net_address, a.client_tcp_port, a.local_net_address, a.local_tcp_port, 
    	b.login_time, b.login_name, b.host_name, b.program_name, b.status, 
    	b.total_scheduled_time, b.total_elapsed_time, b.reads, b.writes, b.logical_reads,
    	substring(d.text, c.statement_start_offset/2 + 1,
    		((case when c.statement_end_offset = -1 then len(d.text) * 2 
    		      else c.statement_end_offset end) - c.statement_start_offset)/2 + 1) as current_sql,
    	d.text as full_sql
    from sys.dm_exec_connections a, sys.dm_exec_sessions b, sys.dm_exec_requests c cross apply sys.dm_exec_sql_text(c.sql_handle) d
    where a.session_id = b.session_id
    and b.session_id = c.session_id
    and b.session_id > 50;


    sqlserver-queries.png


    查询返回的主要信息:

    • client_net_address: 客户端IP

    • status

    • login_name: 登录名

    • current_sql: 当前执行的SQL

    • full_sql: 完整的sql(存储过程或batch的完整sql)


    查询阻塞的会话信息


    通过如下SQL可以查询当前被阻塞的会话、SQL


    SELECT
    	Blocking.session_id as BlockingSessionId, 
    	Sess.login_name AS BlockingUser, 
    	BlockingSQL.text AS BlockingSQL,
    	Waits.wait_type WhyBlocked,
    	Waits.wait_duration_ms,
    	Blocked.session_id AS BlockedSessionId,
    	USER_NAME(Blocked.user_id) AS BlockedUser,
    	BlockedSQL.text AS BlockedSQL,
    	DB_NAME(Blocked.database_id) AS DatabaseName
    FROM sys.dm_exec_connections AS Blocking 
    	INNER JOIN sys.dm_exec_requests AS Blocked ON Blocking.session_id = Blocked.blocking_session_id
    	INNER JOIN sys.dm_os_waiting_tasks AS Waits ON Blocked.session_id = Waits.session_id
    	RIGHT OUTER JOIN sys.dm_exec_sessions Sess ON Blocking.session_id = sess.session_id
    	CROSS APPLY sys.dm_exec_sql_text(Blocking.most_recent_sql_handle) AS BlockingSQL
    	CROSS APPLY sys.dm_exec_sql_text(Blocked.sql_handle) AS BlockedSQL
    ORDER BY BlockingSessionId, BlockedSessionId


    sqlserver-connections.png


    返回的信息:

    • BlockingSessionId

    • BlockingSQL:blocking sql并不一定是真正引起阻塞的SQL,而是阻塞session执行的最后一个SQL。

    • WhyBlocked:阻塞原因

    • wait_duration_ms: 阻塞时间(毫秒)

    • BlockedSessionId:被阻塞的session id

    • Blocked SQL:被阻塞的session执行的SQL



    相关文章

    配置跨集群互信

    1.源集群修改项创建跨域krbtgt Principal进入kadmin命令行,执行以下2条命令:(如有加密算法需要添加加密算法部分)addprinc krbtgt/源集群realm@目标集群real...

    docker网络介绍

    docker网络介绍

    一、docker网络介绍安装docker时,会自动创建三个网络。可以使用docker network ls命令列出这些网络Docker内置这三个网络,运行容器时,可以使用--network标志来指定容...

    为什么根据时间戳获取topic的offset为空呢

    为什么根据时间戳获取topic的offset为空呢

    一、前言最近有一个需求,要查询某一时间戳对应的offset值,于是就想到了使用 ./bin/kafka-run-class.sh kafka.tools.GetOffsetShell --time &...

    MySQL运维实战(2.4) SSL认证在MySQL中的应用

    MySQL支持使用tls进行通信。tls主要有几个作用对客户端、服务端之间的通信数据进行加密。包括客户端发往服务端的SQL,服务端返回给客户端的数据。客户端可以验证服务端的身份。服务端也可以验证客户端...

    大数据自动化巡检系统(一)

    大数据自动化巡检系统(一)

    一、产品简介EasyCare大数据自动化巡检平台是袋鼠云自研的一款大数据集群自动化巡检调优运维平台,支持针对各类大数据组件、服务接口、其他组件等可用性、稳定性进行自动巡检,实现主动实时监控,准确定位问...

    Kafka 单条日志传输大小

    kafka 对于消息体的大小默认为单条最大值是1M 但是在我们应用场景中, 常常会出现一条消息大于1M,如果不对kafka 进行配置。则会出现生产者无法将消息推送到kafka 或消费者无法去消费kaf...

    发表评论    

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。