背景

客户反映HIS数据库在11点出现了长时间的阻塞,直到手动KILL掉阻塞的源头。请我们协助分析原因,最终定位到.NET程序中使用的SqlDataReader未正常关闭导致。

现象

登录SQL专家云,进入趋势分析,在活动会话中回溯11点一个小时内的运行情况,从11:28开始出现阻塞情况,一直持续到11:57。

转到活动会话原始数据,看到ID为418的会话是阻塞源头,阻塞了会话722,会话722又阻塞了其它大量的会话。

分析

首先分析阻塞的成因,会话418执行的是一个查询语句,在表上都加了NOLOCK查询提示,也就是说不加共享锁,不会阻塞其它会话对该表的INSERT、UPDATE、DELETE操作,但是还是要加架构共享锁的,而会话722执行的是TRUNCATE TABLE SYS_KSDMK,是要对表加架构排他锁的,产生互斥,从而造成阻塞。

接下来再分析为什么会造成这么长时间的阻塞,在不同时间点看会话418的运行情况,每个时间点的等待资源都是ASYNC_NETWORK_IO,CPU时间和逻辑读次数都非常小,而且一直不变。

 

ASYNC_NETWORK_IO从字面上有很强的迷惑性,第一反应是网络环境的问题,通过微软官方文档看到,客户端程序因为各种原因无法快速接收使用查询返回的数据也是很重要的原因。和客户进行确认,这个语句查询的都是字典表,数据量非常小,因此判断该查询语句在SQL Server端很快就执行完了,客户端程序在接收查询结果时出现异常。

 

根据推断,在客户端程序中果然找程序的错误日志。查看代码,程序用SqlDataReader逐行接收并处理查询结果,在数据类型转换时有报错。

为了更好的说明这个现象,特地写了一段演示代码。用SqlDataReader循环逐行接收查询返回的结果,当接收到ID>500的数据行时抛出异常。报错后程序无法运行到reader.Close()和connection.Close()来关闭SqlDataReader和SqlConnection。

 1 private void Demo(string connectionString)
2 {
3 SqlConnection conn = new SqlConnection(connectionString);
4 conn.Open();
5 SqlCommand command = conn.CreateCommand();
6 command.CommandText = "SELECT id, a, b FROM [dbo].[Table_2] WITH(nolock) ORDER BY id";
7 SqlDataReader reader = command.ExecuteReader();
8 while (reader.Read())
9 {
10 int id = Convert.ToInt32(reader["id"]);
11 string a = reader["a"].ToString();
12 if (id > 500)
13 {
14 throw new Exception("故意抛出异常");
15 }
16 }
17 reader.Close();
18 conn.Close();
19 }

因为程序没有异常处理机制,该连接(会话)已经被泄露,所以该会话和请求会一直存在,状态如下图。其它会话对表进行TRUNCATE TABLE操作时就会被阻塞。

 

解决

要修改应用程序,增加程序的健壮性。可以在异常处理时检查并关闭SqlDataReader和SqlConnection,也可以利用using的特性自动关闭。

 1 //利用using特性,即使有异常也可以关闭SqlDataReader和SqlConnection
2 private void Demo(string connectionString)
3 {
4 using (SqlConnection conn = new SqlConnection(connectionString))
5 {
6 conn.Open();
7 SqlCommand command = conn.CreateCommand();
8 command.CommandText = "SELECT id, a, b FROM [dbo].[Table_2] WITH(nolock) ORDER BY id";
9 using (SqlDataReader reader = command.ExecuteReader())
10 {
11 while (reader.Read())
12 {
13 int id = Convert.ToInt32(reader["id"]);
14 string a = reader["a"].ToString();
15 if (id > 500)
16 {
17 throw new Exception("故意抛出异常");
18 }
19 }
20 reader.Close();
21 }
22 conn.Close();
23 }
24 }

自动查杀会话

因为很多客户是购买软件厂商的产品,修改程序不容易实施。因此只能在数据库端进行补偿性的措施,例如配置一个定期运行的自动查杀会话的作业,根据这种会话的特征KILL掉。也可以在SQL专家云中启用自动查杀会话的功能。

北京格瑞趋势科技有限公司是聚焦于数据服务的高新技术企业,成立于2008年,创始团队及核心技术人员来自微软和雅虎。微软数据平台金牌合作伙伴,卫宁健康数据平台战略合作伙伴。通过产品+服务双轮驱动的业务模式,14年间累计服务4000+客户,覆盖互联网、市政、交通、电信、医疗、教育、电力、制造业等各个领域。

 

 

为什么带NOLOCK的查询语句还会造成阻塞的更多相关文章

  1. 深入学习MySQL 01 一条查询语句的执行过程

    在学习SpringCloud的同时,也在深入学习MySq中,听着<mysql45讲>,看着<高性能MySQL>,本系列文章是本人学习过程的总结,水平有限,仅供参考,若有不对之处 ...

  2. EF5中 执行 sql语句使用Database.ExecuteSqlCommand 返回影响的行数 ; EF5执行sql查询语句 Database.SqlQuery 带返回值

    一: 执行sql语句,返回受影响的行数 在mysql里面,如果没有影响,那么返回行数为  -1 ,sqlserver 里面  还没有测试过 using (var ctx = new MyDbConte ...

  3. 利用带关联子查询Update语句更新数据

    Update是T-sql中再简单不过的语句了,update table set column=expression  [where condition],我们都会用到.但update的用法不仅于此,真 ...

  4. 通过带参数的Sql语句来实现模糊查询(多条件查询)

    #region 通过带参数的Sql语句来实现模糊查询(多条件查询) StringBuilder sb = new StringBuilder("select * from books&quo ...

  5. (转)经典SQL查询语句大全

    (转)经典SQL查询语句大全 一.基础1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql s ...

  6. 经典SQL查询语句大全

    一.基础1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份数 ...

  7. T-SQL查询语句(二):嵌套查询

    一个select...From...Where查询语句块可以嵌套在另一个select...From...Where查询块的Where子句中,称为嵌套查询.外层查询称为父查询,主查询.内层查询称为子查询 ...

  8. T_SQL查询语句(一): 单表查询

    ############################################ 查询语句--SELECT ########################################## ...

  9. ES 常用的查询语句介绍

    elasticsearch定义了两种查询方式: 一.索引(index).type.document 相关语句 1.列出所有索引的状态 GET /_cat/indices?v health status ...

  10. mybatis查询语句的背后之参数解析

    转载请注明出处... 一.前言 通过前面我们也知道,通过getMapper方式来进行查询,最后会通过mapperMehod类,对接口中传来的参数也会在这个类里面进行一个解析,随后就传到对应位置,与sq ...

随机推荐

  1. 手写promise异步状态修改then方法返回来的结果

    看看下面这一段代码返回来的是什么??? <body> <script type="text/javascript"> let p = new Promise ...

  2. linux如何配置ssh密钥登录

    为什么要用ssh密钥登录 购买的服务器设置密码很容易被暴力破解,用密钥登录安全很多.root用户新建的用户也要用密钥登录更安全,如果一直su - 用户名登录 不方便 用xftp等服务上传文件到用户使用 ...

  3. vue脚手架创建与环境安装

    1.安装 Node.jsDownload | Node.js 在这里下载的是最新版,如果要安装以前的版本,页面往下拉找到 Previous Releases-Donloads-下载msi文件. ​​ ...

  4. ActiveReports报表行号

    =RunningValue(Fields!字段名称.Value, CountDistinct, "矩表分组名称") RunningValue(Fields!区域.Value, Co ...

  5. 解决pycharm编辑超大超大项目时CPU占用100%

    在编辑py文件时,cpu占用100%其实和内存的关系不大,因为这个现象是间歇性的,不是持续的. 我试过给pycharm分配16GB的内存,也是一样没有缓解CPU占用高. 项目和pycharam也都是存 ...

  6. LyScript 实现绕过反调试保护

    LyScript插件中内置的方法可实现各类反调试以及屏蔽特定API函数的功能,这类功能在应对病毒等恶意程序时非常有效,例如当程序调用特定API函数时我们可以将其拦截,从而实现保护系统在调试时不被破坏的 ...

  7. 深入浅出Java多线程(四):线程状态

    引言 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第四篇内容:线程状态.大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在现代软件开发中,多线程编程已经成为提升 ...

  8. 予力八六三软件应用现代化,提升DevSecOps效能,探索交付之路

    本文分享自华为云社区<予力八六三软件应用现代化,提升DevSecOps效能,探索全球交付之路>,作者: HuaweiCloudDeveloper. 来源:<华为云DTSE>期刊 ...

  9. React框架运行机制

    React框架运行主流程 1.JSX是JS语言的扩展,被babel编译后,会转换成React.creatElement(),这个方法返回的是一个虚拟DOM. 2.将虚拟DOM渲染到真实DOM的方法是R ...

  10. CH59X/CH58X/CH57X sleep模式下串口唤醒收发数据

    整体程序逻辑: 下方的具体程序及使用是基于CH592进行的 SLEEP模式睡眠唤醒是由协议栈管理的,还在睡眠时,无法接收到数据. 已经通过使能HAL_SLEEP开启睡眠.如果需要在睡眠时实时接收串口传 ...