ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

数据库查询慢的五大层级排查:从硬件到锁并发

数据库查询慢的五大层级排查:从硬件到锁并发 一条本来20毫秒就能返回的SQL突然变成5秒业务方在群里连环追问你打开数据库一看CPU没爆、内存没满、数据量也没涨多少——这种情况我见过太多次了。很多人第一反应是“加索引”但加完索引发现还是慢甚至更慢。数据库查询速度的影响因素从来不是单点问题它涉及硬件、表结构、SQL写法、系统参数、并发控制好几个层面任何一个环节出问题都可能让查询彻底“翻车”。这篇文章我把这几十个影响因素按层级拆开结合实际排查经验说清楚每层怎么定位、怎么修适合后端开发、DBA、运维以及正在自己维护数据库系统的人参考。1. 影响查询速度的五大层级先看清瓶颈在哪一层1.1 为什么“一慢就加索引”总是不奏效先说一个观察我接触过的很多项目遇到查询变慢第一反应都是往索引上堆好像索引是万能膏药。但真相是索引只是影响查询速度的其中一个因素甚至很多时候不是主因。如果一条SQL走了正确的索引依然慢问题大概率出在数据量级、锁竞争、系统资源或执行计划偏离上这时候再加索引不仅没用反而会增加写入开销和存储成本。索引的本质是B树它解决的问题是“减少扫描的数据量”。但一条查询的完整链路是客户端发SQL → 数据库连接器 → 解析器 → 优化器生成执行计划 → 执行器调用存储引擎 → 存储引擎访问缓冲池/磁盘 → 返回结果。每一步都可能成为瓶颈。你加了索引优化器却可能因为统计信息过期没用它索引没问题缓冲池命中率却低得可怜每次都要走磁盘SQL规划没问题却因为另一个事务持有行锁查询一直卡在等待状态。这些都不是“加索引”能解决的。1.2 分层的排查框架从硬件到SQL再到并发我习惯把影响查询速度的因素分成五层硬件资源层、表结构设计层、SQL写法层、数据库配置层、锁和并发层。这五层不是孤立的而是层层叠加的。比如表结构设计差会导致SQL要扫描大量数据于是CPU和IO占用飙升最后表现为“硬件资源不够”。如果只盯着最表面的硬件层去扩容问题可能暂时缓解但根因还在过段时间数据量再涨一点又会复发。所以排查的时候我的建议是从上往下看先确认是不是系统资源到达了上限再去看SQL和索引接着看配置最后看锁和事务。不是每一次都要五层全查但心里必须有这张地图才不会被表象带偏。后面几章我就按这个框架一层一层拆开讲。2. 硬件与基础环境地基不牢索引再好也白搭2.1 CPU、内存、磁盘和网络的量化影响硬件因素最容易被忽略因为它的表现很隐蔽。CPU影响的是“计算能力”比如排序、Join、聚合这些操作都要吃CPU。如果你有一条SQL要排序几十万行但服务器只有2核那再好的索引也救不了排序本身的开销。内存影响的是“缓存能力”关系型数据库全靠内存缓冲池扛读写内存不够就意味着频繁刷盘和淘汰表现就是查询延迟抖动有时候快有时候慢。磁盘影响的是“底层IO能力”这一块的差距非常直观。普通机械盘随机IOPS只有几百入门级SSD能做到几万企业级NVMe能到几十万。同一张表在机械盘上全表扫描要30秒在NVMe上可能只要3秒。网络则影响跨节点查询和读写分离场景下的往返延迟比如应用连数据库走的是跨网段路由光网络RTT就有几十毫秒这个延迟是SQL怎么优化都消不掉的。如果你遇到查询慢可以先看一眼top命令里的CPU状态和iostat里的磁盘利用率和await值。CPU用户态高说明在跑计算逻辑io wait高说明在等磁盘这些都是硬件层最直接的信号。再配合看数据库的“缓冲池命中率”——MySQL的innodb_buffer_pool_reads和innodb_buffer_pool_read_requests两个状态值一除就能算出来命中率长期低于95%甚至99%就该考虑内存层面的事了。2.2 冷热数据与缓存命中率为什么重启后“第一次查询特别慢”还有一个非常典型的现象数据库刚重启完第一次跑一条平时只要10毫秒的查询结果卡了几百毫秒甚至几秒。这不是SQL变笨了而是缓冲池和操作系统页缓存都是空的数据要从磁盘重新加载一遍这就是冷缓存命中。之后数据慢慢被加载到内存又恢复到了10毫秒。这个现象在教育用户和排查问题时特别有用。如果一条查询只在“数据库刚重启后”或“清理缓存后”变慢那大概率不是SQL问题而是数据预热不够。解决思路也明确要么让系统运行一段时间自然预热要么在业务低峰期主动把常用表扫一遍把数据搬进内存。千万不要因为一次重启后的慢查询就去重构SQL或者调整索引那样是拿大炮打蚊子。在实际运维中我还见过因为机器迁移、容器重建导致整个数据库实例从物理机换到新宿主结果业务连着几天查询变慢的案例。表象是“查询慢”根因是宿主机的CPU型号和磁盘类型发生了变化整体算力下降了。所以硬件层的排查不只是看当前负载还要对比变化前后的环境差异这类“软因素”往往比单纯看监控数字更容易被漏掉。3. 索引与表结构设计决定查询速度的第一变量3.1 B树索引的核心逻辑为什么“有索引却没用上”比“没有索引”更常见索引这块值得单独拿出来细说因为80%以上的查询性能问题都跟索引选择有关。B树索引的查找过程可以理解为在一棵多叉树上做二分查找高度通常只有3到4层所以走主键索引查一行数据几次IO就能完成。但索引能发挥作用的前提是优化器认为走索引比全表扫描更便宜并且查询条件里的列真的能被索引覆盖。我见过最多的问题是“明明有索引执行计划却走了全表扫描”。常见原因有几个第一统计信息过期优化器手里的数据分布还是一个月前的它估算全表扫描只要扫1万行实际有100万行结果选错了路。第二对索引列做了函数运算比如WHERE DATE(create_time) 2025-01-01索引在create_time上但函数让索引列变成了一个临时计算结果索引直接失效。第三隐式类型转换比如索引列是varchar查询条件传了整数数据库为了比较类型会把索引列做转换同样走不了索引。所以在讨论“查询慢”之前第一步永远是看执行计划里到底用的什么访问路径。执行计划里如果出现ALL全表扫描、Using filesort、Using temporary这些标志再强的硬件也扛不住数据量增长。3.2 联合索引、覆盖索引与最左前缀原则联合索引是另一个容易踩坑的点。假设你在(a, b, c)三个列上建了一个联合索引那它实际生效的规则是“最左前缀原则”也就是说查询条件里必须命中a接下来才能依次命中b、c。如果直接写WHERE b ? AND c ?这个联合索引基本用不上因为索引树的第一层排序字段是a你得跳过a去查bB树就没法二分定位了。覆盖索引则是“锦上添花”的设计如果查询只需要a、b两列而索引正好包含这两列那数据库可以直接从索引叶子节点取数据连回表都省了。这种优化对高频、重复的小查询特别有效代价是索引会占用更多存储空间所以也不能无脑把所有列都塞进索引。我实际做优化的时候会先看业务里最频繁的查询条件是什么再反推联合索引怎么建。比如订单表最常见的查询是WHERE user_id ? ORDER BY create_time DESC LIMIT 10那一个(user_id, create_time)的联合索引就比分别建两个独立索引要好得多既能等值过滤又能排序。3.3 关于视图能否加快查询速度普通视图不会物化视图才会经常有人问“建视图是不是能让查询快点”这个说法我得先澄清一下。普通视图只是一个命名的SQL定义它不存储数据你查一个视图数据库还是会实时执行视图背后的SQL把它当成子查询去处理。所以普通视图对查询速度没有任何正向帮助它只是能把复杂的SQL语义封装起来让代码更可读而已。真正能加速的是物化视图它会预先计算并把结果存成一张物理表。查询物化视图时数据已经算好了速度当然快。但物化视图也有代价数据源变化后它需要刷新刷新不及时就会读到旧数据。MySQL原生物化视图支持有限但Oracle、PostgreSQL、人大金仓这些数据库都支持。如果你的业务是“底层表频繁写入报表类查询却要对大量历史数据做聚合”那物化视图是性价比很高的方案比在业务层做缓存更不容易出错。3.4 字段类型、表分区与反范式哪些改动能产生肉眼可见的效果字段类型的影响比很多人想象得要严重。比如一个状态字段本来只需要tinyint却用了varchar(20)每次查询都要做字符比较占用的索引空间也更大再比如说主键用随机UUID字符串InnoDB的聚簇索引在插入时会出现大量页分裂和随机写数据量一大查询随机访问的磁盘IO也会跟着变多。如果主键没有特殊业务要求用自增整数或有序的分布式ID比UUID更适合InnoDB的索引结构。表分区适合“数据量大但查询条件能明确切到分区键”的场景。比如日志表按月分区查询时指定了月份数据库能直接做分区裁剪只扫一个月的文件而不是全表。但分区不是万能的如果查询条件不带分区键分区表反而可能因为要扫描的分区过多而更慢。反范式设计则适用于高并发读场景比如订单详情页需要同时查订单表和商品表与其每次join不如在订单表里冗余几个商品字段用空间换时间。这个手段能显著降RT但会让数据一致性维护变复杂是否采用要看业务容忍度。4. SQL写法与执行计划同样的需求性能差百倍4.1 先从EXPLAIN看起读懂执行计划里的关键几列SQL写法的优化绕不开执行计划。MySQL里最常用的是EXPLAIN SELECT ...PostgreSQL里是EXPLAIN ANALYZE SELECT ...Oracle则是EXPLAIN PLAN FOR。执行计划里最关键的是type一列它直接告诉你这条查询是怎么访问数据的从最好到最差大概是system、const、eq_ref、ref、range、index、ALL。在这里我做个速查说明const和eq_ref通常意味着走了主键或唯一索引几乎是最优状态ref是普通索引等值查询也很好range是范围查询比如大于、小于、betweenindex是全索引扫描比全表好一点但也不算高效ALL就是全表扫描数据量大时基本是灾难。还有一个必看的是Extra列。如果出现Using filesort说明SQL里的ORDER BY没利用上索引排序数据库要额外做一次排序操作出现Using temporary说明查询用了临时表通常和GROUP BY、DISTINCT关联出现Using index反而是好事说明覆盖索引生效了不需要回表。看到这些关键字基本就能判断出这条SQL写完以后会怎么跑。4.2 select * 的隐患与隐式类型转换两种最常见的“慢SQL”SELECT *在开发过程中写起来很爽但在生产环境里它经常会拖累查询。原因是它会把所有列的数据都读出来哪怕业务只要两列。数据从存储引擎返回、经过网络传到应用的每一环都在搬运多余的数据。如果表里有几个text或blob大字段这种浪费会被放得更大。我之前优化过一条报表SQL只是把SELECT *改成只取需要的列查询时间直接下降了40%因为减少了大字段的IO读取。隐式类型转换我前面提了一句这里具体展开。比如索引列是varchar类型你却传了整形参数MySQL会先对索引列做转换再去比较转换之后索引失效全表扫描。反过来的情况也一样索引列是整数你传了字符串那通常还好因为数据库会把传入值转成数字。但为了保险起见应用层的参数类型必须和表结构保持一致尤其是从接口层拿到的参数很多是字符串不要放任它直接进SQL。4.3 分页深翻、JOIN和IN/EXISTS的选择写法不同成本完全不同分页深翻页是另一个高频坑。LIMIT 100000, 20这个写法不是只查20行而是要先扫出前100020行再丢弃前100000行。越往后翻扫描量越大响应越慢。优化手段通常有两种一种是“游标分页”不写页码只传上一页最后一条记录的排序值比如WHERE create_time ? ORDER BY create_time DESC LIMIT 20另一种是“延迟关联”先只查主键再回原表取数据SELECT t.* FROM t JOIN ( SELECT id FROM t ORDER BY create_time DESC LIMIT 100000, 20 ) tmp ON t.id tmp.id;这样子查询先在索引上快速定位主键再根据20个主键回表多表关联的代价就小得多。关于IN和EXISTS很多老文章说“大表用EXISTS小表用IN”但这个说法在现代优化器面前已经不够准确了。优化器会把IN改写成半连接也可能把EXISTS改成物化方式真正靠谱的做法还是看执行计划。如果IN后面的子查询返回结果集很小那IN通常没问题如果子查询结果集很大EXISTS往往更划算。实践上我会先用执行计划确认再用实际耗时来判断而不是靠经验拍脑袋。4.4 参数化查询与SQL复用别把简单问题搞复杂参数化查询PreparedStatement对性能有两方面的帮助。第一是安全能防止SQL注入第二是复用执行计划。数据库对一条SQL生成执行计划是有代价的如果能反复利用同一个计划解析和优化的开销就能省下来。尤其是高并发场景下应用层用拼接字符串的方式生成SQL每次都是一个新SQL文本优化器只能反复编译CPU损耗很可观。这一点在Oracle里特别敏感因为硬解析比软解析成本高很多。在MySQL里参数化查询配合预处理语句也能减少SQL文本传输量。在TDengine这类时序数据库里官方还提供了taos_stmt_prepare这类绑定接口目的也是为了参数化写入、减少解析开销。所以无论是写业务代码还是写数据接入程序尽量用参数化接口这不仅是一个习惯问题更是一个能直接降低数据库CPU消耗的手段。5. 数据库配置与系统参数默认值适合跑通不一定适合跑快5.1 内存、临时表、排序区三大容易被忽视的配置数据库安装完大多用默认配置能跑通但跑得快完全是另一回事。MySQL的innodb_buffer_pool_size很多小型项目默认只有128M甚至更小如果机器内存有32G这个机会完全被浪费了。一般建议设为物理内存的60%到70%但也不能设满要给操作系统和其他进程留余地。PostgreSQL的参数思路略有不同shared_buffers通常建议设置为物理内存的25%左右因为PostgreSQL重度依赖操作系统的页缓存不是把内存全塞进自己的共享缓冲区就好。排序和Join操作还有单独的内存区比如MySQL的sort_buffer_size、join_buffer_sizePostgreSQL的work_mem。这类参数有个特点它按“每个操作”分配如果全局并发很多内存消耗会被放大。把work_mem从1MB调到1GB不是让你拥有1GB排序内存而是每个排序都可能吃1GB并发20个就爆了。所以这类参数要谨慎调整我的原则是在满足常用查询不落盘的前提下尽量小。临时表空间也经常被忽略。GROUP BY和部分DISTINCT操作会产生临时表MySQL默认的临时表存储引擎是内存但数据超过阈值后就会落到磁盘用tmpdir指定的目录。如果那个目录空间不足或磁盘性能差查询也会明显变慢。检查一下临时文件是不是落在了机械盘上把tmpdir挪到SSD优化效果常常出乎意料。5.2 连接池到底开多大不是越大越好连接池大小是个经典误区。很多人的直觉是“连接越多越好并发不够就加”但真实情况是每个数据库连接都要占用内存、可能对应一个线程或进程而且数据库本身有锁和各种内部队列。连接数超过阈值后增加连接只会增加上下文切换和锁等待吞吐量反而下降。业界常用的经验值是连接数 CPU核数 × 2 磁盘数。假设机器是8核大约20个连接就能跑到不错的性能。这个数字和很多人想象中完全不一样但它背后的逻辑是——每个查询真正在跑的只有少量CPU资源超过这个量级后等待时间就远大于执行时间。实际项目里很多高并发服务把连接池限制在20到50之间配合应用内的队列性能反而稳定。如果你现在用的是200甚至500的连接池上限建议先从CPU核数去反推一个合理值再看平均RT有没有改善。5.3 慢查询日志与执行计划把“证据”先收集起来排查慢查询第一步永远是先收集证据。MySQL开启慢查询日志很简单SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;long_query_time设为1意思是超过1秒的查询都会被记下来。在业务高峰期跑一段时间慢查询日志里出现频率最高的那几条就是最值得优化的对象。PostgreSQL则可以通过修改postgresql.conf里的log_min_duration_statement来记录慢语句效果类似。拿到慢SQL样本后逐个加EXPLAIN分析基本就能定位到索引或写法问题。规划慢查询日志时还要注意日志文件增长问题。生产环境不建议永久开启通常只在排查期间开几天用完之后及时关掉或轮转清理避免日志量把磁盘打满。更稳妥的做法是接入监控平台比如PrometheusGrafana采集数据库状态指标把慢查询数量、锁等待时延、缓冲池命中率这些指标做成大盘问题发生的时候有历史曲线可看比事后去翻日志高效得多。6. 锁、事务与并发查询也会被“人”挡住6.1 锁的类型与阻塞查询不一定慢在数据量也可能慢在等待有些查询执行计划完美、索引高效、数据量也不大可它就是慢。这时候就要考虑一个经常被忽略的因素锁等待。数据库锁的本质是多事务并发访问同一资源时的协调器。InnoDB里有共享锁和排他锁读读兼容读写互斥写写互斥。如果一个事务修改了一行但还没提交另一个事务想更新同一行就必须等前面的锁释放。这个“等锁”的时间会计入查询耗时但执行计划完全看不出来。排查时看SHOW PROCESSLIST或SHOW ENGINE INNODB STATUS能看到当前查询的状态是Waiting for lock。在PostgreSQL里可以查pg_stat_activity里的wait_event字段如果大量会话阻塞在一个锁上性能问题就变成了并发控制问题这时候去优化SQL本身是没有意义的。6.2 事务隔离级别、MVCC与长事务并发场景下的深坑事务隔离级别直接影响加锁的范围。标准级别有四种读未提交、读已提交、可重复读、串行化。MySQL默认是可重复读为了在可重复读下避免幻读InnoDB引入了间隙锁间隙锁会锁住一个范围而不仅仅锁住命中的行。间隙锁是死锁和锁等待的一大来源。PostgreSQL默认是读已提交整体锁冲突要小一些。MVCC则让普通读不会阻塞写、写也不会阻塞读这大大提升了并发能力。但要注意MVCC依赖的是undo日志和事务快照一条长事务如果一直不提交它会持有一个老快照导致undo日志无法清理表膨胀查询扫描的版本链越来越长光做SELECT也会变慢。这种问题用索引优化无效只能从业务层面去拆解事务里只放必要的操作、避免事务内做远程调用和用户交互长事务一定尽早提交或回滚。6.3 死锁与锁等待排查从进程列表里看真相死锁指的是两个事务各自持有锁又都在等对方的锁形成一个循环。数据库检测到死锁后会牺牲其中一个事务让它回滚并报错。应用日志里看到“Deadlock found”就是这种情况。但死锁不是只能靠报错发现在死锁发生前通常有大量锁等待在积累。日常排查锁问题我建议按这个顺序先看当前活跃会话MySQL执行SHOW FULL PROCESSLISTPostgreSQL执行SELECT pid, state, wait_event_type, wait_event, query FROM pg_stat_activity;确认哪些会话卡在等待锁。再看事务表MySQL的information_schema.innodb_trx能列出当前所有事务的开始时间和等待的锁。最后根据等待关系定位是哪个长事务堵住了其他人找到源头之后和业务方沟通确认是否可以终止它。提示生产环境执行KILL或pg_terminate_backend要谨慎终止长事务可能导致业务报错但如果不终止系统可能持续恶化。一般先和业务确认或选择在业务低峰期处理。7. 常见问题速查与排查流程实录7.1 一张速查表对应常见症状的原因我把这些年碰到的“查询慢”现象和对应原因整理成了一张速查表排查的时候可以直接对照现象最可能的原因下一步动作偶发慢重启后更明显缓冲池/OS Cache冷预热数据、调整缓冲池CPU飙升整体卡顿慢SQL全表扫描或排序量大抓慢日志、看执行计划只某几张表查询越来越慢统计信息过期/索引失效收集统计信息、重建索引高峰期慢低峰正常连接池打满/锁等待查会话状态、看锁等待读写分离后偶尔读到旧数据主从同步延迟调整同步策略、实时性要求高的走主库一条SQL偶发等待几秒锁等待查事务表、定位长事务数据库显示“存疑”状态SQL Server数据库状态异常先恢复数据库可用性再谈优化这张表的价值在于提供一个检查顺序让你不是从头开始瞎猜。大部分查询慢问题都能从这六七个典型场景里找到对应项。7.2 排查慢查询的黄金顺序从现象到根因我个人的排查习惯是固定顺序的不乱跳第一步看系统层CPU、内存、IO等待、网络延迟确认有没有资源耗尽。第二步开慢查询日志或者从监控平台拉最近的TOP SQL。第三步看执行计划确认访问路径是走索引还是全表扫。第四步确认统计信息是否过期很多数据库需要定期ANALYZE或OPTIMIZE TABLE统计信息不准会让优化器做出错误判断。第五步检查锁和事务排除并发干扰。第六步再回头验证优化效果同一个SQL跑三次取平均值对比。这个顺序看起来简单但只要严格执行基本能把问题定位在某一层。最怕的是没看系统负载就开始改SQL或者没看锁就开始调参数最后改了几天发现根本不相关。7.3 特殊场景数据库状态异常与主从延迟的干扰项数据库“存疑”suspect状态是SQL Server特有的现象数据库文件损坏或磁盘异常时会出现表现为数据库不可访问、相关查询全部失败。这种情况和“查询慢”是两类问题如果现场是查询直接报错而不是变慢要先确认数据库状态再考虑后续的恢复和文件检查。主从延迟则是另一个容易混淆的“慢”来源。当系统做了读写分离主库负责写入从库负责查询如果同步软件跟不上主库的写入速率从库上的数据就会“过期”。业务侧的表现是“查询返回了旧数据”或者“刚提交的数据查不到”虽然这不是性能问题但给用户的体感就是系统出了问题。排查方法也比较简单在主从两边对比SHOW SLAVE STATUS里的Seconds_Behind_Master如果持续非零说明同步链路有瓶颈需要检查网络、磁盘IO和从库自身的执行效率。8. 几个特定数据库与辅助工具的场景化补充8.1 国产数据库人大金仓、达梦的优化习惯把人大金仓和达梦单独拿出来说是因为这两年国产化替换越来越多很多团队从Oracle或MySQL迁移过去遇到查询变慢时会有点手足无措。但我的经验是它们的核心引擎设计大量借鉴了Oracle和PostgreSQL的思路SQL语法兼容度也很高所以常见的优化手段是通用的。执行计划照常能看只是命令细节略有差异统计信息同样需要定期收集索引、视图、物化视图的概念也基本一致。比较需要注意的是初始配置。很多国产数据库在安装时使用的是保守参数比如内存缓冲设得很小、最大连接数设得不高迁移之后如果不调整性能可能比原库差一大截。我的建议是迁移完成后立刻做一轮参数摸底把缓冲池、排序区、连接池这些和业务规模匹配起来再结合慢查询日志做一轮验证。8.2 时序数据库TDengine与轻量库SQLite别用关系型思维时序数据库不能直接套用关系型数据库的优化方法。比如TDengine它的核心优势在时间分区、标签索引和聚合下推查询优化重点应该放在设计合理的表结构按设备或指标建模、合理设置分区时长以及尽量把聚合计算下推到数据库里执行而不是把原始数据全部拉回应用再算。这种场景下关系型数据库里的“多建索引”思路完全不适用乱建索引只会增加写入开销和存储占用。SQLite则是一个极端注重轻量级的单文件数据库常用于嵌入式设备或本地工具。它的查询优化同样依赖索引甚至可以通过EXPLAIN QUERY PLAN查看执行计划但因为它是嵌入式库并发的性能上限远不如服务端数据库。如果你发现SQLite查询慢排查方向很简单先确认有没有建合适的索引再确认是不是频繁写入导致WAL文件膨胀最后看查询本身是否能把数据量控制在合理范围。把SQLite当重型服务端数据库来调优容易陷入“怎么调都差不多”的困境。8.3 善用数据库管理工具可视化执行计划与索引健康检查市面上的数据库管理工具比如dbx这一类已经不只是“连上跑SQL”的客户端了。它们能直接展示执行计划图标让你一眼看出哪一步是全表扫描、哪一步是排序操作还能列出每张表的索引使用情况和冗余索引。对于不太习惯读EXPLAIN文本的人来说这种可视化方式非常有用能更快把问题定位到具体节点。但工具始终是辅助核心还是要理解背后的原理。比如工具标红了一个全表扫描你还是要判断它是“真的该建索引”还是“因为返回大部分数据本来就该全表扫”。我用这类工具的习惯是先用它们做大盘的筛选和识别找到可疑SQL后再回到数据库命令行里做精准的EXPLAIN和耗时测试。两边结合效率最高。我自己做性能排查这十几年最深的体会是查询速度从来不是一个单一指标而是一条完整的链路每个环节都有它的“木桶短板”。不要迷信某一个调优手段能解决所有问题也不要因为一次优化效果明显就把手段无限放大。多用执行计划确认事实多用慢查询日志收集证据少凭直觉改东西数据库自然会给到你对应的回报。最后分享一个小习惯每次解决完一个慢查询问题我都会把现象、原因、执行计划、解决手段整理成一小段记录下次再遇到类似的“貌似无关”的症状先翻自己的历史笔记往往能少走很多弯路。
返回列表