DotTrace系列:5. 诊断程序的 慢File 和 慢SQL
一:背景
1. 讲故事
上一篇跟大家聊到了 UI Freeze 的问题,让大家感受到了时间轴的强大和美观,这个是 perfview 所不具备的,本篇跟大家聊一下用 dottrace 诊断Windows子系统模块(File,SQL),虽然perfivew也能做这些,毕竟都是基于ETW机制,但前者占据了可观性,后者占据了信息的完整性,大家在实践上根据需要综合使用吧。
二:子系统模块诊断
1. 如何寻找 慢File
有一天你发现自己的生产程序有一段时间特别卡,一时也找不到原因,后来你通过监控发现程序在卡的时候,磁盘使用量明显变高,读取达到了 125M+/s ,截图如下:

找到了蛛丝马迹之后,接下来就可以上 dottrace 了,为了防止信息有遗漏,我们选用 External .NET Process 模式,然后输入我们监控的 ConsoleApp4.exe程序, 即程序后启动模式,截图如下:

故障复现之后可立即停止收集,打开收集文件,选择 File Operations 之后观察时间轴,可以看到主线程上有大片的深蓝色,说明3~22s这个时间段有大量的文件读写,接下来选中这个时间段,截图如下:

从卦象上可以看到很多信息。
- SubSystems:File I/O 占比 99.9%
- Direction: 只有读没有写,看样子读很猛。
- FileName:原来是对 1GB_LogFile.log 文件的读取。
- Hotspots:TestInefficientReading 方法占比 99.9%,问题方法无疑了。
找到问题方法之后,在方法上右键选择 Show Code 即可观察到源代码,参考如下:
static void TestInefficientReading(string filePath)
{
Stopwatch sw = Stopwatch.StartNew();
long totalBytesRead = 0;
// 最差的实现方式:逐字节读取
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
int b;
while ((b = fs.ReadByte()) != -1) // 逐字节读取
{
totalBytesRead++;
}
}
sw.Stop();
Console.WriteLine($"\n低效方式读取完成,总字节数: {totalBytesRead}");
Console.WriteLine($"总耗时: {sw.Elapsed.TotalSeconds:F2}秒");
Console.WriteLine($"读取速度: {(totalBytesRead / (1024 * 1024) / sw.Elapsed.TotalSeconds):F2} MB/s");
}
从卦中代码看,这是对文件按逐字节读取的方式,有些朋友可能有疑问,现在的 SSD 读取不都是 几G几G 的读取吗?怎么才1G的文件要读取 5.8s,说不通哈,其实这里还有一些干扰因素,第一个是SSD都有理论值,第二个是dottrace在开启ETW时会有额外开销,不然你的诊断数据从哪里得来的?
接下来关掉 ETW,直接运行程序,你会发现程序有 近3倍 的提升,截图如下:

2. 如何诊断慢 SQL
很多时候做程序的性能优化,有一个不容忽视的点就是观察下程序没有没出现一些慢SQL,慢SQL的危害很多,如果是同步访问容易引发线程饥饿,如果是异步访问容易导致托管堆产生过多的 Overlapped 引发托管堆碎片,进而导致内存占用过高,内存过高又会引发程序频繁的GC,最终导致程序的性能低下,有一句话叫 蝴蝶效应,就是这样的真实再现。。。
接下来就是如何诊断慢SQL,如果在 SERVER 端直接开启那这个影响面就比较大,谨慎起见还是在 Client 端临时开启来点对点的针对优化,当然这东西的本质也是借助 ETW 的,而这个 ETW 只针对微软自家的 SQL SERVER,这个是有些遗憾。。。
使用 dottrace 的 timeline 模式,打开追踪文件,选择 SQL Queries 事件,观察多个线程之间的时序,看样子 SQL 都是异步哈,截图如下:

为了寻找慢SQL,观察 SQL Queries: Command 筛选器中的SQL列表,很快就找到了一个 2s 的SQL,同时也看到了它是由 FullTableScanAsync 方法产生的,截图如下:

可以点击右键 Show Code 观察方法的源代码,参考如下:
static async Task FullTableScanAsync(SqlConnection connection)
{
var cmd = new SqlCommand(
@"-- 添加2秒延迟
WAITFOR DELAY '00:00:02';
SELECT *
FROM Orders
WHERE OrderStatus = 'Processing'
ORDER BY OrderDate DESC", connection);
using (var reader = await cmd.ExecuteReaderAsync())
{
int count = 0;
while (await reader.ReadAsync())
{
count++;
if (count % 100 == 0) Console.Write(".");
}
Console.WriteLine($"\n找到 {count} 条处理中的订单");
}
}
到这里可能有人会提一个问题, Command 面板中的 SQL 是截断的,我想观察 SQL 的全貌怎么办?毕竟这是真实项目的切实需求,可以点击 View -> SQL Queries 打开,找到目标SQL之后可以copy出来,截图如下:

三:总结
用 dottrace 对程序做性能优化,效率其实还是蛮高的,而且对容易引发性能瓶颈的IO和SQL这两大模块也处理的非常好,点赞!
作为JetBrains社区内容合作者,如有购买jetbrains的产品,可以用我的折扣码 HUANGXINCHENG,有25%的内部优惠哦。

DotTrace系列:5. 诊断程序的 慢File 和 慢SQL的更多相关文章
- 安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项
安装SQL2008时遇到"未能加载文件或"file:///d:microsoft..sql.chainer.packagedata.dll"或它的某个依赖项,如下图所示 ...
- Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用
Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...
- Stream系列(十五)File方法使用
文件读写 视频讲解:https://www.bilibili.com/video/av78612785/ EmployeeTestCase.java package com.example.demo; ...
- 搞懂前端二进制系列(二):🍈File、FileReader与Base64
参考资料: JavaScript高级程序设计第四版:File API https://juejin.cn/post/7046313942938812424[前端二进制一次搞清楚] 一.File 类型 ...
- [每天解决一问题系列 - 0002] Xcopy cannot copy file with long directory
现象: 当xcopy的文件的全名(包括目录和文件名)的长度超过255字符时,会copy失败,得到insufficient memory错误 解决方法: 在Server 版的OS中,有robcopy命令 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (12) -----第三章 查询之使用SQL语句
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-2使用原生SQL语句更新 问题 你想在实体框架中使用原生的SQL语句,来更新底层 ...
- 数据分页处理系列之一:Oracle表数据分页检索SQL
关于Oracle数据分页检索SQL语法,网络上比比皆是,花样繁多,本篇也是笔者本人在网络上搜寻的比较有代表性的语法,绝非本人原创,贴在这里,纯粹是为了让"数据分页专题系列"看起 ...
- Pyspark中遇到的 java.io.IOException: Not a file 和 pyspark.sql.utils.AnalysisException: 'Table or view not found
最近执行pyspark时,直接读取hive里面的数据,经常遇到几个问题: 1. java.io.IOException: Not a file —— 然而事实上文件是存在的,是 hdfs 的默认路径 ...
- MySql系列:中文写入数据库出现错误java.sql.SQLException: Incorrect string value: '\xE5\xxxx' for column 'xxxx' at row 1及其解决方法
在将kft-activiti-demo的数据库连接改为mysql之后,可以正常登陆,但是在新建请假流程的时候出现如下错误: Caused by: java.sql.SQLException: In ...
- MySQL学习系列一---命令行连接mysql和执行sql文件
1.命令行连接mysql #mysql -h(主机) -u(用户名) -p (数据库名) mysql -hlocalhost -uroot -p testdb Enter password: **** ...
随机推荐
- Delphi 执行一个外部程序,当外部程序结束后言主程序立即响应
delphi 执行一个外部程序,当外部程序结束后言主程序立即响应 我们经常能看到360安全卫士进行windows系统升级时,执行windows升级程序,当升级程序执行完成后,360马上弹出提示框.这样 ...
- [每日算法] leetcode第88题:合并两个有序数组
leetcode第88题入口 题目描述 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目. 请你 合并 ...
- 【Ubuntu】在Ubuntu上配置Java环境
[Ubuntu]在Ubuntu上配置Java环境 壹.前言 Java是运用得非常广泛的编程语言,在使用Linux时难免会碰到需要用到JDK的情况,故本文介绍如何在Ubuntu上配置Java21环境. ...
- RESTful的连接时间超时时间设定
dsResrful的连接方式时,如何设定timeout呢? DSRestConnection.HTTP.ConnectTimeout := 5000; 就这么简单.因为封装的indy的TidHTTP. ...
- 【U-Boot】解决U-Boot的“Unknown command 'help' - try 'help'”问题
[U-Boot]解决U-Boot的"Unknown command 'help' - try 'help'"问题 零.起因 最近在玩U-Boot,自己编译U-Boot之后输入hel ...
- 一文带你深度剖析什么叫Transformer
Transformer概述 Transformer是基于自注意机制(self-attention)的神经网络模型.其经常用于来处理时序数据.我们知道还有另外的常用的两类深度神经网络模型循环神经网络(R ...
- 基于OpenCV与PyTorch的智能相册分类器全栈实现教程
引言:为什么需要智能相册分类器? 在数字影像爆炸的时代,每个人的相册都存储着数千张未整理的照片.手动分类不仅耗时,还容易遗漏重要瞬间.本文将手把手教你构建一个基于深度学习的智能相册分类系统,实现: 三 ...
- 康谋分享 | 自动驾驶联合仿真——功能模型接口FMI(终)
在之前的文章中,我们介绍了如何构建简单的车辆模型,并基于FMI2.0构建了其FMU,其最终结构为: 今天将会和大家分享如何在aiSim中,通过UDP和aiSim车辆动力学API(Vehicle Dyn ...
- 为了掌握设计模式,开发了一款Markdown 文本编辑器软件(已开源)
设计模式实战项目:Markdown 文本编辑器软件开发(已开源) 一.项目简介 项目名称:YtyMark-java 本项目是一款基于 Java 语言 和 JavaFX 图形界面框架 开发的 Markd ...
- 适用于LixtBox的,开启UI虚拟化时,某些时候需要定位到还没加载的项,比如自动选中某项,视图自动移过去等等
1 /// <summary> 2 /// 将指定父级的下级索引元素,显示在视野下,使其可见 3 /// </summary> 4 /// <param name=&qu ...