我在字节当主管:百次面试结果,总结一个刷掉99%求职者的问题!
前言
我一个在大厂当主管的朋友,跟我说:
“现在招性能测试太难了,当然不是说没人干,一开招聘信息就能收到一大把简历,其中不乏学历亮眼、背景出色、简历里各种高并发、大流量的项目经验的人才。
问题在于,当你提出讲一个项目中遇到的性能问题,以及如何分析定位时,却发现绝大多数根本没有遇到过性能问题。
甚至面试了几个高级性能测试工程师,还是发现一旦涉及到性能分析调优,就开始左顾右盼、答非所问。”
“问题的结症在于,大部分面试者参与的性能测试项目就不多,企业又希望招有经验的测试,这本身就存在矛盾!”
我说,你说的情况谁不知道?你不如讲点实际的,讲点经验,性能调优你说怎么弄?
朋友思考了一会说道:“那不如正好聊聊我手上的这个项目,聊聊SQLSERVER数据页!”
“什么是数据页 ”
一般来说,对大块资源或者数据进行高效管理都会按照一定粒度来划分的,比如说 Windows 对内存的管理就是按照 内存页 (4k) 来进行划分,言外之意就是 SQLSERVER 对 mdf 的管理也是按照 数据页 (8k) 来划分的,画个图大概就是这样的。
![](https://img-blog.csdnimg.cn/img_convert/003396d5ff1447bda6fbd1cbb9235a76.png)
那如何来验证这个结论呢?刚才也说了数据都在数据页上,我们弄点数据然后在指定的数据页上提取出来就好了,这里用的是 SQLServer 2019
![](https://img-blog.csdnimg.cn/img_convert/291c4c49792c4cadb398a9da5903d02e.png)
一般来说,对大块资源或者数据进行高效管理都会按照一定粒度来划分刚才图中也说了 mdf 是由无数个 数据页 拼出来的,那如何找到 person 表所在的数据页呢?其实微软提供了一个 dbcc ind 命令可以帮我们洞察出来,同时记得开始3604标记,让输出显示在控制台上,而不是默认的错误日志中,这个命令具体怎么用,大家可以查看官方文档。
![](https://img-blog.csdnimg.cn/img_convert/00838220506c4b89aef762d78c5d5d53.png)
![](https://img-blog.csdnimg.cn/img_convert/8310078bbad74bb985321ec451fade0c.png)
从输出看有两条记录,第一个是 PagePID=41 是 IAM 数据页,而PagePID=280 就是我们 person 表记录所在的数据页编号,也就是说 person 表的记录在 mdf 文件偏移为 0n280 * 0n8192 的位置,用 WinDbg 算一下就是 0x00230000 。
![](https://img-blog.csdnimg.cn/img_convert/0983742061e548e0930fe26db632eaf8.png)
那是不是呢?可以用 WinHex 验证一下,为了不出现进程占用,先把 MyTestDB 下线了,最后记得再上线即可
![](https://img-blog.csdnimg.cn/img_convert/305cdaacd9ee4dbd8e47e6458fd518e8.png)
![](https://img-blog.csdnimg.cn/img_convert/fc67876f1ec34ceeb632f15e245c3aa9.png)
从WinHex 上看,果然是在偏移为 0x00230000 这个数据页上。
“如何从内存中看到数据页”
刚才我们看到的数据页只是物理硬盘上的,但数据页和数据页之间的逻辑关系肯定是在内存中用一定的数据结构来承载的,接下来看下这个 数据页 映射到 SQLSERVER 进程内存的哪里呢?微软提供了 DBCC PAGE 命令可以查看指定 数据页 的详细信息。
![](https://img-blog.csdnimg.cn/img_convert/0072b8a49ab940d4ad50ef8ca394c0ff.png)
输出结果如下:
DBCC执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。PAGE: (1:280)BUFFER:BUF@0x000002B41104F480bpage = 0x000002B3F0632000 bPmmpage = 0x0000000000000000 bsort_r_nextbP = 0x000002B41104F3D0bsort_r_prevbP = 0x0000000000000000 bhash = 0x0000000000000000 bpageno = (1:280)bpart = 1 ckptGen = 0x0000000000000000 bDirtyRefCount = 0bstat = 0x9 breferences = 0 berrcode = 0bUse1 = 12454 bstat2 = 0x0 blog = 0x15ab215absampleCount = 0 bIoCount = 0 resPoolId = 0bcputicks = 0 bReadMicroSec = 182 bDirtyContext = 0x0000000000000000bDbPageBroker = 0x0000000000000000 bdbid = 10 bpru = 0x000002B3FA708040PAGE HEADER:Page@0x000002B3F0632000m_pageId = (1:280) m_headerVersion = 1 m_type = 1m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8200m_objId (AllocUnitId.idObj) = 179 m_indexId (AllocUnitId.idInd) = 256 Metadata: AllocUnitId = 72057594049658880 Metadata: PartitionId = 72057594043170816 Metadata: IndexId = 0Metadata: ObjectId = 581577110 m_prevPage = (0:0) m_nextPage = (0:0)pminlen = 13 m_slotCnt = 2 m_freeCnt = 8060m_freeData = 128 m_reservedCnt = 0 m_lsn = (37:584:3)m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0m_tornBits = -116446693 DB Frag ID = 1 Allocation StatusGAM(1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED PFS (1:1) = 0x41 ALLOCATED 50_PCT_FULLDIFF(1:6) = CHANGED ML (1:7) = NOT MIN_LOGGED DATA:MemoryDump @0x000000F840DF8000000000F840DF8000: 01010000 00820001 00000000 00000d00 00000000 ....................000000F840DF8014: 00000200 b3000000 7c1f8000 18010000 01000000 ........|...........000000F840DF8028: 25000000 48020000 03000000 00000000 00000000 %...H...............000000F840DF803C: 1b2a0ff9 00000000 00000000 00000000 00000000 .*..................000000F840DF8050: 00000000 00000000 00000000 00000000 10000d00 ....................000000F840DF8064: 01000000 6a6f686e 20020000 10000d00 02000000 ....john ...........000000F840DF8078: 6d617279 20020000 00002121 21212121 21212121 mary .....!!!!!!!!!!000000F840DF808C: 21212121 21212121 21212121 21212121 21212121 !!!!!!!!!!!!!!!!!!!!000000F840DF80A0: 21212121 21212121 21212121 21212121 21212121 !!!!!!!!!!!!!!!!!!!!...000000F840DF9FF4: 21212121 21212121 70006000 !!!!!!!!p.`.OFFSETTABLE:Row- Offset 1 (0x1) - 112 (0x70) 0 (0x0) - 96 (0x60) DBCC执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。Completiontime: 2022-12-30T17:48:20.5466040+08:00
从上面的 Memory Dump 区节中可以看到,数据在进程内存的 000000F840DF8064 ~ 000000F840DF8078 范围内,这里要吐槽的是内存地址按照 大端布局 的,看起来很不习惯,可以用 windbg 用 小端布局 来显示。
![](https://img-blog.csdnimg.cn/img_convert/df91ef95564043e1a33b5cfe6460f367.png)
“sql 请求源码研究”
喜欢玩 windbg 的朋友肯定想对 sqlserver 进行汇编级洞察,比如研究下 sql 请求在 sqlserver 里面的执行流是什么样的?其实很简单,我们可以这样处理,使用 ba 对 john 的内存地址下一个硬件断点,即 ba r4 000000f840df8064+0x4,然后在 SSMS 上执行一条 SELECT * FROM person 语句,因为要提取 john 自然就会命中。
![](https://img-blog.csdnimg.cn/img_convert/f436635344b049aaaec4b7ae69d177e9.png)
从线程栈上看,有 SQLSERVER 核心的 Scheduler ,Task 以及 命令分析器,查询优化器,查询执行器 等各种核心元素,后续再慢慢研究吧。
“总结”
深入的理解数据,索引在数据页上的布局,可以从根本上帮助我们理解如何减少请求在数据页上的流转,减少逻辑读,从而提升 sql 的查询性能。
相关文章
- js arrayBuffer 字节序问题,小端法,大端法
- 在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。 (#1113)
- Kotlin 朱涛-3 原理 编译器 反编译 字节码
- AOP AspectJ 字节码 示例 Hugo MD
- 放弃40 万年薪从字节裸辞,告别 996 拥抱 955…
- SQL 宽字节注入详解
- 2022最新Android面试题及答案整理(共计4176页PDF)包含腾讯、字节、百度、小米、阿里等大厂面试真题
- Java学习路线-26:字节流与字符流OutputStream/InputStream/Writer/Reader
- 【Android 插件化】Hook 插件化框架 ( 创建插件应用 | 拷贝插件 APK | 初始化插件包 | 测试插件 DEX 字节码 )
- 理解大小端字节序
- 字节序
- 字节面试官心声:个个都说会自动化,结果面试一问细节全露馅了
- 8年字节软件测试工程师感悟:与薪资相匹配的永远是实力
- 字节跳动测试岗面试记:2面被按地上血虐,所幸Offer已到手...
- 验证码是自动化的天敌?看看3年字节经验的测试工程师是怎么解决的
- 【刷题记录11】Java工程师丨字节面试真题(五)
- 字节、百度、美团、腾讯技术面,面试题及答案分享(Android岗)
- 太惨了,前端字节面试一面挂,你看我还有机会吗?