自学编程第69天:慢SQL排查与联合索引优化实战
发布时间:2026/10/8 9:23:04 作者:尧图编辑部 阅读量:1,286

学习日记写到了第69天说实话这个数字我自己都有点恍惚。两个月前我还在纠结“要不要转行学编程”现在已经能把一个带用户登录、商品列表、购物车结算的全栈小项目完整跑起来今天甚至为了解决一条慢SQL在数据库优化上死磕了一整天。这篇日记既是给我自己的复盘也想分享给同样在自学编程、每天记录进度的人——第69天不是一个神奇节点但它足够说明一个道理把学习拆成每天都能执行的小块持续输出记录进步是肉眼可见的。这篇日记会围绕我今天的核心任务展开为什么我在这个阶段突然开始补数据库索引的原理一条实际出现的慢查询是怎么被定位和优化的以及这69天里踩过的那些坑——包括技术上的更多是心态上的。如果你也处于自学的中期阶段正在从“跟着教程敲代码”过渡到“独立解决真实问题”这篇内容应该能给你不少可以直接抄作业的参考。1. 69天学习路线全回顾从零基础到能做项目的节奏把控1.1 前两个月的学习框架与选型逻辑很多人问我自学编程第一件事是不是选编程语言我的真实答案可能和你想的不太一样第一件事是定学习框架。我指的不是技术框架而是“学到什么程度算会了”“学多久开始做项目”“每天投入多少时间”这三件事。没有这三个锚点很容易陷入今天学Python明天看Java后天又去刷CSS的混乱状态。我给自己定的路线很朴素主语言选Python后端框架选FastAPI数据库选MySQL前端只用基础的HTML/CSS/JavaScript配合一个现成的后台模板。这套组合的理由很简单——第一Python的语法门槛低能把精力集中在逻辑而不是语言的奇技淫巧上第二FastAPI自带交互式接口文档调试接口时非常直观对于新手来说能看到请求和响应的全貌比什么都重要第三MySQL是应用最广的关系型数据库工作里大概率会碰到早学早受益。前30天我只做一件事把Python的基础语法、函数、类、文件操作和异常处理过了一遍同时每天写一个10到30行的小脚本。这些脚本不求复杂但必须当天运行出结果。第31天到第50天进入后端开发跟着官方文档把FastAPI的路由、参数校验、依赖注入、数据库会话管理摸了一遍。第51天开始我不再学新知识而是用已经掌握的内容做一个简单的商品管理后台今天第69天我还在这个项目上迭代。这套节奏背后有一个我特别想强调的逻辑到了中期阶段新的知识点必须服务于手头的真实项目。如果你今天学到的东西不能立刻用在项目里那就先不学记到“待办清单”里等需要时再回头查。我见过太多人花三个月刷完所有网课最后连一个完整项目都拿不出来原因就是学习和应用脱节了。1.2 每天的固定学习节奏与时间分配我每天的安排基本是固定的这69天几乎没有变过。早上起床后花一个小时看文档或技术文章只做输入不做输出下午拿出两到三个小时敲代码这个时段是黄金时间所有动手的工作都集中在这里晚上用一个小时写学习日记把当天学到的内容用自己的话整理一遍顺便截图记录关键代码和运行结果。这套节奏的核心在于“晚上那一个小时”。写日记不是流水账而是强制自己复述当天学的内容——这其实就是费曼学习法的简化版如果你不能把一个概念用自己的话讲清楚说明你还没真懂。我经常遇到这种情况白天觉得自己完全理解了“事务隔离级别”晚上写日记时却发现压根解释不清“脏读”和“不可重复读”的区别那第二天就得回头补。没有日记这个反馈机制我可能稀里糊涂地带着错误理解继续往下走等真正做项目时才爆雷。时间分配的比例也是有讲究的输入和输出的时间比我控制在1比3左右。学一个小时至少留三个小时来写代码和排错。很多自学者的问题不是学得太少而是练得太少看视频的时候觉得“我都会了”一关掉视频打开编辑器就大脑空白。今天第69天我已经基本摆脱了这种“视频依赖症”看到需求第一反应是自己先尝试实现而不是马上去搜教程。2. 今日重头戏数据库索引原理与实际选型2.1 为什么要学索引慢查询带来的第一个瓶颈今天早上我本来计划给项目增加一个“按用户查看历史订单”的功能结果遇到了一个之前没认真对待的问题订单表的数据量才几千条某条查询竟然要180毫秒。对于几千条数据的表来说这个速度是绝对不能接受的。我的第一个反应是检查代码逻辑排查了半天发现问题不在业务代码而是SQL本身在做全表扫描。于是我被迫开始认真研究数据库索引。这里我用自己的话解释一下索引的原理数据库中的数据和索引的关系可以粗浅地类比成一本厚厚的字典。没有索引时你想找一个字只能从第一页翻到最后一页这叫全表扫描有索引时你直接通过“拼音目录”或“部首目录”定位到目标页这就是索引的作用。MySQL的InnoDB引擎默认使用的B树索引本质上就是把这本字典的目录做成了多级结构查询时从根节点一路往下经过的中间节点数量非常少。我当时遇到的具体问题SQL大概是这样的从订单表里查某个用户最近30天的订单并且按照下单时间倒序排列。把SQL丢到数据库里一执行慢就慢在“按用户ID过滤”这一步数据库不知道哪个用户在哪个数据页只能把整张表的所有行都读一遍挨个判断是不是目标用户。这个操作的时间复杂度是O(n)n是表的行数数据量一旦上来比如十万、百万行单次查询就会变成秒级甚至更糟。这里有一个关键点我一开始没理解创建了索引不等于索引一定被用上。数据库有一个查询优化器它会根据统计信息决定走索引还是全表扫描统计数据不准确或者SQL写法有问题都可能导致优化器放弃索引。这也就是为什么光会建索引不够还得会看SQL的执行计划。2.2 索引类型对比与适用场景下午我专门花了两个小时整理了一张索引选型的心得表把几种常用索引的定位和适用场景理清楚。这里分享给同样在自学的朋友索引类型作用典型使用场景注意事项主键索引唯一标识一行数据每张表都应该有主键优先使用自增整数或UUID不要用业务字段做主键唯一索引保证字段值唯一用户名、手机号、订单号插入重复数据时数据库会直接报错普通索引加速字段查询被频繁用于WHERE过滤的字段不是越多越好每个索引都有维护成本联合索引同时加速多个字段的查询用户ID下单时间这种组合过滤必须遵循最左前缀原则全文索引文本内容的关键词检索商品描述、文章正文数据量大时性能下降明显专业场景可考虑搜索引擎我今天的订单查询问题实际最合适的方案就是建一个“用户ID下单时间”的联合索引。为什么不建两个单列索引你如果只按用户ID建索引数据库会先查出该用户的所有订单再对结果进行时间排序排序时如果数据量比较大就要用到临时文件和文件排序操作这正是慢的第二个原因。联合索引则能做到先精确定位用户又在索引内部天然保持时间有序查询和排序一次性解决。联合索引有一个新手最容易踩的坑叫“最左前缀原则”。比如我建的是(用户ID, 下单时间)联合索引那么只有查询条件里带着用户ID时索引才会生效如果只传下单时间不传用户ID索引就用不上。原理也不难理解联合索引就像查电话簿先按姓氏排序再按名字排序你只告诉它名字它是没法直接定位的。今天我对这个原则的体会比看十篇文章都深刻因为我是真的看着执行计划从“全表扫描”切到“索引查找”才彻底搞明白的。3. 实操记录一条慢SQL的完整排查与优化过程3.1 复现慢查询与执行计划分析下午两点我开始正式处理那条慢SQL。第一步不是改代码而是把慢查询稳定复现出来。我先开了MySQL的慢查询日志配置方法是修改数据库配置文件在mysqld部分加上三行设置开启慢查询日志开关把阈值设成0.1秒指定日志文件路径。配好后重启MySQL服务再跑一遍业务接口日志里果然抓到了那条SQL。第二步是分析这条SQL为什么慢工具是EXPLAIN语句。把EXPLAIN加在SQL前面执行数据库会返回一张表格上面有十几个字段新手看这张表最容易懵我先只抓四个关键字段type、key、rows、Extra。当时返回的结果让我印象很深type那一列写的是ALL意思是全表扫描key是NULL说明没有用到任何索引rows估算扫描了三千多行虽然绝对值不大但已经能预见到表数据量再涨十倍后的灾难Extra里出现了Using filesort意味着这条SQL还要额外做一次文件排序。四个字段的解释合起来就是一条慢SQL的完整自白没有索引、全表扫描、还要临时排序不慢才怪。诊断到这里我确定解决方案就是加联合索引。但我不急着执行因为我想验证一下自己最左前缀原则的理解。我故意先只建了一个“下单时间”的单列索引重新跑EXPLAIN结果发现type还是ALL索引根本没被用上。原因就是查询条件里首先出现的字段是用户ID而不是下单时间数据库优化器认为走时间索引还要回头过滤大量数据不如直接扫全表。这个“故意踩坑”的过程很有价值它让我真正理解了一个结论索引不是建了就生效优化器才最终说了算。3.2 索引优化前后的性能对比明确了方案后我执行了真正的优化操作。在订单表上创建联合索引命令是一行很短的SQL在指定的两个字段上建联合索引索引命取成能看出用途的名字方便后面维护时一眼识别。建完索引我立刻重新跑了一遍EXPLAIN结果变化非常直观type从ALL变成了ref这在索引类型里算是效率不错的一种表示通过普通索引的非唯一列精确定位key变成了刚建的索引名称rows从三千多行降到了个位数意味着数据库只需要扫描确认几个候选行Extra里的Using filesort也消失了因为索引内的数据天然已经按下单时间排好序。我对效果做了三次实际计时取平均值优化前单次查询约180毫秒优化后约8毫秒性能提升了一个数量级以上。这个数据让我非常震撼因为我以前总觉得“优化”是性能工程师才关心的事情没想到一个初中级开发也能通过一行SQL获得如此显著的提升。但这里我必须提一句索引的代价这也是今天学到的最实在的权衡观念索引不是免费的。每建一个索引每次对表执行插入、更新、删除操作时数据库都要额外维护这个索引结构。也就是说查询变快的同时写入会变慢磁盘空间也会被多占。所以之前学到的那句“索引不是越多越好”背后是有实际代价支撑的如果一个字段几乎不会被当作查询条件给它建索引就是纯亏。这也是为什么建索引前一定要先分析真实的查询模式而不是把所有字段都加上索引。另外今天还顺手处理了一个相关的细节在复合查询场景里如果只查两个固定字段而不需要回表拿整行数据可以考虑把查询需要的字段也放进索引这就叫覆盖索引。它能进一步减少数据库的随机访问次数。如果查询的字段超出了索引的范围数据库每命中一条索引记录都还要到主键索引里回查一次完整数据这个操作叫回表是性能上的一个隐性成本。知道这个概念后再看很多SQL优化文章里说的“避免select星号”就容易理解多了——只查你需要的列实际上是在帮助索引更高效地工作同时也在减少网络传输和内存开销。4. 这69天里我踩过的坑与排查心得4.1 学习心态上的三个大坑如果说技术坑可以通过查资料解决那么心态坑才真正劝退人。第一个大坑是教程依赖症也叫“马不停蹄地看视频、迟迟不动手”。我前两周基本就是这个状态收藏了几十个教程每天都觉得“知道了好多新东西”实际上代码能力几乎没有增长。我后来强制自己执行一个规则看一个小时的视频必须拿出至少两小时独立敲代码而且不能照着视频敲要自己关掉画面从头写。这个规则帮我戒掉了视频依赖。第二个大坑是攀比焦虑。学习群里总有“30天拿到大厂offer”的人也总有“三个月做了五个项目”的别人家孩子。第20天左右我曾因为这种比较差点放弃觉得自己进度慢、天赋差。后来我想明白一个事学习日记是写给昨天的自己看的不是写给别人的。我拿今天写的代码和昨天写的代码对比只要确实有进步就值得肯定。第69天回头看当初那些“大神”很多也没坚持下来真正留下来的反而是像我这样每天默默记录的人。第三个大坑是“只学不用学了就忘”。我前一个月学的很多函数和库现在完全不记得了因为当时只是跟着教程跑了一遍没有在真实场景里用过。后来我调整了策略所有新知识必须找到一个“为什么现在需要它”的理由。比如今天学索引是因为我的项目真的出现了慢查询如果我还没遇到这个问题单纯为了学而学大概率一周后就忘了B树是怎么回事。这个策略让我的学习效率高了很多因为每个知识点都带着真实的上下文进入记忆想忘都难。4.2 技术细节上的避坑清单除了心态这69天我也积累了一套技术层面的避坑方式。环境问题曾经是最消耗我精力的事情Python版本不统一、虚拟环境忘了激活、依赖包版本冲突每一个都能耗掉一个小时。后来我养成了两个习惯每个项目单独建虚拟环境用文件管理依赖遇到环境问题先在终端里打印关键变量的版本信息而不是凭感觉瞎猜。编码问题也是新手重灾区。我第一次读CSV文件时中文乱码折腾了很久才发现是文件编码不是默认的UTF-8格式正确做法是读取时明确指定编码方式。类似的坑还包括窗口环境下的换行符差异、数据库连接字符串里的字符集参数漏配。这些问题都不难解决但排查过程很费时间所以我现在写代码时会习惯性地在涉及外部文件、数据库、网络请求的地方主动检查一下编码配置。还有个很容易被忽略的习惯是代码备份。我早期因为一个误操作删掉了自己写了两天的项目文件差点崩溃。现在我把项目代码都放进Git仓库每天结束学习前提交一次写上今天的日期和做了什么事。这不仅防丢代码还有一个额外好处翻看提交历史就能看到自己的成长轨迹。第1天的提交可能只有几个文件几百行代码第69天的提交已经是一个完整项目了这种记录带来的成就感比任何鸡汤都管用。调试技巧方面我目前用得最多的还是“二分注释法”。当接口报错时不要从上到下逐行看而是先根据错误信息定位到可能出错的那一个函数在函数入口打印输入参数在关键分支打印中间结果最后打印输出。三步下来基本能锁定问题。实在定位不到的就用日志把错误详细信息完整记录下来信息越完整的报错越好查。我犯过的最大错误就是只看控制台的第一行错误忽略了后面的堆栈信息导致多花半小时在错误的地方找原因。5. 把学习日记坚持下来的方法第69天我的真实心得最后一个部分我想聊聊坚持本身。很多人私信问我“你是怎么做到每天都写的”其实我的方法一点都不神秘把写日记变成一个不需要意志力的习惯。我固定了写日记的时间和工具每天电脑一打开新建文档的动作已经变成了肌肉记忆同时降低当天的写作门槛不强求写长文哪怕是三句话加两张截图也算完成记录。一旦某天因为特殊原因中断我不会第二天花双倍时间弥补而是照常写当天的内容宁可中间空一天也不让“补日记”变成负担。日记的内容我也有一套固定模板帮助自己快速落笔今天我学到了什么今天哪个问题困扰了我超过一小时明天我最重要的三件事是什么。这个小模板让我每天都能留下三个维度的痕迹——新知识、难问题和下一步计划。一个月后回看那些“困扰我超过一小时”的问题往往能串成一条清晰的成长线索最初是环境搭不起来然后是语法记不住再后来是接口联不通最近开始变成性能优化和架构设计了。看到这条线索的变化你会对自己的进步产生非常具象的认知。今天写到这里我又看了一眼项目的运行日志那条8毫秒的查询安静地躺在记录里和上午那条180毫秒的慢SQL形成了鲜明的对比。如果有人问我第69天到底学到了什么核心技术我会说数据库索引确实重要但比这更重要的是我学会了一套发现问题、定位问题、解决问题的流程而这个过程恰恰是自学者最稀缺、也最难通过教程获得的能力。接下来我打算继续推进项目把订单模块的分页查询和统计报表做好如果顺利的话第70天的日记应该就是怎么给报表接口设计合理的查询参数了。