热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

我在字节当主管:百次面试结果,总结一个刷掉99%求职者的问题!

我一个在大厂当主管的朋友,跟我

我一个在大厂当主管的朋友,跟我说:

“现在招性能测试太难了,当然不是说没人干,一开招聘信息就能收到一大把简历,其中不乏学历亮眼、背景出色、简历里各种高并发、大流量的项目经验的人才。

问题在于,当你提出讲一个项目中遇到的性能问题,以及如何分析定位时,却发现绝大多数根本没有遇到过性能问题。

甚至面试了几个高级性能测试工程师,还是发现一旦涉及到性能分析调优,就开始左顾右盼、答非所问。”

“问题的结症在于,大部分面试者参与的性能测试项目就不多,企业又希望招有经验的测试,这本身就存在矛盾!”

我说,你说的情况谁不知道?你不如讲点实际的,讲点经验,性能调优你说怎么弄?

朋友思考了一会说道:“那不如正好聊聊我手上的这个项目,聊聊SQLSERVER数据页!”

“什么是数据页 ”

一般来说,对大块资源或者数据进行高效管理都会按照一定粒度来划分的,比如说 Windows 对内存的管理就是按照 内存页 (4k) 来进行划分,言外之意就是 SQLSERVER 对 mdf 的管理也是按照 数据页 (8k) 来划分的,画个图大概就是这样的。

那如何来验证这个结论呢?刚才也说了数据都在数据页上,我们弄点数据然后在指定的数据页上提取出来就好了,这里用的是 SQLServer 2019

CREATEDATABASE MyTestDBGOUSE MyTestDB;GOIF OBJECT_ID('person') IS NOT NULLDROPTABLE person;CREATETABLE person(idINTIDENTITY,nameCHAR(5));GOINSERT INTO dbo.person( name ) VALUES ('john');INSERTINTO dbo.person( name ) VALUES ('mary');

“寻找数据所在的数据页”

一般来说,对大块资源或者数据进行高效管理都会按照一定粒度来划分刚才图中也说了 mdf 是由无数个 数据页 拼出来的,那如何找到 person 表所在的数据页呢?其实微软提供了一个 dbcc ind 命令可以帮我们洞察出来,同时记得开始3604标记,让输出显示在控制台上,而不是默认的错误日志中,这个命令具体怎么用,大家可以查看官方文档。

DBCCTRACEON(3604)DBCCIND(MyTestDB,person, -1)

从输出看有两条记录,第一个是 PagePID=41 是 IAM 数据页,而PagePID=280 就是我们 person 表记录所在的数据页编号,也就是说 person 表的记录在 mdf 文件偏移为 0n280 * 0n8192 的位置,用 WinDbg 算一下就是 0x00230000 。

0:090> ? 0n280 * 0n8192Evaluateexpression: 2293760 = 00000000`00230000

那是不是呢?可以用 WinHex 验证一下,为了不出现进程占用,先把 MyTestDB 下线了,最后记得再上线即可。

ALTERDATABASE MyTestDB SETOFFLINEALTERDATABASE MyTestDB SETONLINE

从WinHex 上看,果然是在偏移为 0x00230000 这个数据页上。

“如何从内存中看到数据页”

刚才我们看到的数据页只是物理硬盘上的,但数据页和数据页之间的逻辑关系肯定是在内存中用一定的数据结构来承载的,接下来看下这个 数据页 映射到 SQLSERVER 进程内存的哪里呢?微软提供了 DBCC PAGE 命令可以查看指定 数据页 的详细信息。

DBCCTRACEON(3604)DBCCPAGE(MyTestDB,1,280,2)

输出结果如下:

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 用 小端布局 来显示。

0:116> dp 000000F840DF8064000000f8`40df8064 6e686f6a`00000001000d0010`00000220000000f8`40df8074 7972616d`00000002 21210000`00000220000000f8`40df8084 21212121`2121212121212121`21212121000000f8`40df8094 21212121`21212121 21212121`21212121000000f8`40df80a4 21212121`2121212121212121`21212121000000f8`40df80b4 21212121`21212121 21212121`21212121000000f8`40df80c4 21212121`2121212121212121`21212121000000f8`40df80d4 21212121`21212121 21212121`21212121

“sql 请求源码研究”

喜欢玩 windbg 的朋友肯定想对 sqlserver 进行汇编级洞察,比如研究下 sql 请求在 sqlserver 里面的执行流是什么样的?其实很简单,我们可以这样处理,使用 ba 对 john 的内存地址下一个硬件断点,即 ba r4 000000f840df8064+0x4,然后在 SSMS 上执行一条 SELECT * FROM person 语句,因为要提取 john 自然就会命中。

0:104> ba r4 000000f840df8064+0x40:104> gBreakpoint 0 hitsqlmin!BTreeMgr::GetHPageIdWithKey+0x4a:00007ff8`d4ea121a 48894c2478 mov qword ptr [rsp+78h],rcx ss:000000f8`45278028=00000248000000250:102> k # Child-SP RetAddr Call Site00 000000f8`45277fb0 00007ff8`d4ea0b59 sqlmin!BTreeMgr::GetHPageIdWithKey+0x4a01000000f8`45278450 00007ff8`d4ea08b7 sqlmin!IndexPageManager::GetPageWithKey+0x11902000000f8`45278d20 00007ff8`d4eb22d1 sqlmin!GetRowForKeyValue+0x20303000000f8`45279880 00007ff8`d4eb2a39 sqlmin!IndexDataSetSession::GetRowByKeyValue+0x14104000000f8`45279a70 00007ff8`d4eb279b sqlmin!IndexDataSetSession::FetchRowByKeyValueInternal+0x23005000000f8`45279ed0 00007ff8`d4eb2883 sqlmin!RowsetNewSS::FetchRowByKeyValueInternal+0x43706000000f8`4527a000 00007ff8`d4eaadab sqlmin!RowsetNewSS::FetchRowByKeyValue+0x9607000000f8`4527a050 00007ff8`d4f93d60 sqlmin!CMEDScan::StartSearch+0x4f808 000000f8`4527a170 00007ff8`d4f93f3a sqlmin!CMEDCatYukonObject::GetTemporalCurrentTableId+0x10e09000000f8`4527a380 00007ff8`d801f0d1 sqlmin!CMEDProxyRelation::GetTemporalCurrentTableId+0x7a0a000000f8`4527a3c0 00007ff8`d801dfb8 sqllang!CAlgTableMetadata::FPartialBind+0xb580b000000f8`4527a580 00007ff8`d80394b3 sqllang!CAlgTableMetadata::Bind+0x3170c000000f8`4527a620 00007ff8`d800415d sqllang!CRelOp_Get::BindTree+0x78f0d000000f8`4527a890 00007ff8`d80418a1 sqllang!COptExpr::BindTree+0x850e000000f8`4527a8c0 00007ff8`d800415d sqllang!CRelOp_FromList::BindTree+0x310f000000f8`4527a920 00007ff8`d802c2a3 sqllang!COptExpr::BindTree+0x8510000000f8`4527a950 00007ff8`d800415d sqllang!CRelOp_QuerySpec::BindTree+0x2e811000000f8`4527aa60 00007ff8`d80042dd sqllang!COptExpr::BindTree+0x8512000000f8`4527aa90 00007ff8`d800415d sqllang!CRelOp_SelectQuery::BindTree+0x48913000000f8`4527ab80 00007ff8`d8003f23 sqllang!COptExpr::BindTree+0x8514000000f8`4527abb0 00007ff8`d8004e47 sqllang!CRelOp_Query::FAlgebrizeQuery+0x4bd15 000000f8`4527ae30 00007ff8`d7ff5576 sqllang!CProchdr::FNormQuery+0x8f16 000000f8`4527ae70 00007ff8`d7ff4a79 sqllang!CProchdr::FNormalizeStep+0x5bd17 000000f8`4527b4b0 00007ff8`d7ff5124 sqllang!CSQLSource::FCompile+0xea518000000f8`4527e1b0 00007ff8`d7e659c3 sqllang!CSQLSource::FCompWrapper+0xcb19000000f8`4527e280 00007ff8`d7e6387a sqllang!CSQLSource::Transform+0x7211a000000f8`4527e3e0 00007ff8`d7e6e67b sqllang!CSQLSource::Execute+0x4fa1b 000000f8`4527e8c0 00007ff8`d7e6d815 sqllang!process_request+0xca61c000000f8`4527efc0 00007ff8`d7e6d5ef sqllang!process_commands_internal+0x4b71d000000f8`4527f0f0 00007ff8`d4096523 sqllang!process_messages+0x1d61e 000000f8`4527f2d0 00007ff8`d4096e6d sqldk!SOS_Task::Param::Execute+0x2321f000000f8`4527f8d0 00007ff8`d4096c75 sqldk!SOS_Scheduler::RunTask+0xa520000000f8`4527f940 00007ff8`d40bb160 sqldk!SOS_Scheduler::ProcessTasks+0x39d21 000000f8`4527fa60 00007ff8`d40baa5b sqldk!SchedulerManager::WorkerEntryPoint+0x2a122000000f8`4527fb30 00007ff8`d40bafa4 sqldk!SystemThreadDispatcher::ProcessWorker+0x3ed23 000000f8`4527fe30 00007ff8`f6d86fd4 sqldk!SchedulerManager::ThreadEntryPoint+0x3b524000000f8`4527ff20 00007ff8`f865cec1 KERNEL32!BaseThreadInitThunk+0x1425000000f8`4527ff50 00000000`00000000 ntdll!RtlUserThreadStart+0x21

从线程栈上看,有 SQLSERVER 核心的 Scheduler ,Task 以及 命令分析器,查询优化器,查询执行器 等各种核心元素,后续再慢慢研究吧。

“总结”

深入的理解数据,索引在数据页上的布局,可以从根本上帮助我们理解如何减少请求在数据页上的流转,减少逻辑读,从而提升 sql 的查询性能。


推荐阅读
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • Windows7 64位系统安装PLSQL Developer的步骤和注意事项
    本文介绍了在Windows7 64位系统上安装PLSQL Developer的步骤和注意事项。首先下载并安装PLSQL Developer,注意不要安装在默认目录下。然后下载Windows 32位的oracle instant client,并解压到指定路径。最后,按照自己的喜好对解压后的文件进行命名和压缩。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • mysql-cluster集群sql节点高可用keepalived的故障处理过程
    本文描述了mysql-cluster集群sql节点高可用keepalived的故障处理过程,包括故障发生时间、故障描述、故障分析等内容。根据keepalived的日志分析,发现bogus VRRP packet received on eth0 !!!等错误信息,进而导致vip地址失效,使得mysql-cluster的api无法访问。针对这个问题,本文提供了相应的解决方案。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
author-avatar
先进的山楂4l4_519
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有