数据库调优的10个实战角度:从索引、SQL到锁竞争与架构设计
2026/9/13 7:41:41 网站建设 项目流程

数据库又慢了,接口超时告警一条接一条,开发说是SQL写得有问题,DBA说是表结构设计不合理,运维说硬件也该换了——这种互相甩锅的场面,干过几年后端和数据库的人应该都熟。调优这事确实容易让人一头雾水,因为它没有一个万能公式,不像修bug那样定位到某一行代码就行,而是要在一个复杂的系统里找出真正的瓶颈点。

我自己的体会是,数据库调优与其说是一门技术,不如说是一套排查问题的思路。你得有一个清晰的框架,知道该从哪些角度去审视一套数据库系统,然后按图索骥,逐个排查,才能少走弯路。这篇文章就把我这些年实际干活过程中总结的10个调优角度完整梳理一遍,每个角度都会讲清楚原理、判断方法、实操手段和容易踩的坑。不管你是刚接触数据库的开发者,还是正在处理线上故障的负责人,这套框架都能帮你快速找到入口。

1. 索引优化:调优的第一优先级的理由

索引永远是数据库调优里最先要查的东西。我见过太多性能问题,根本原因就是一个本该走索引的查询在扫全表,或者索引建了但没被用上。这不夸张,至少一半以上的查询慢问题,都出在索引这一层。

1.1 索引为什么能提速,底层逻辑先搞懂

索引的核心数据结构通常是B+树。为什么MySQL这些主流关系型数据库都选B+树而不是哈希表或者普通二叉树?因为B+树有两个特性非常适合磁盘存储:一个是矮胖,层数少。一个几百万行的表,索引树通常也就三四层,查一条数据只需要几次磁盘IO。另一个是叶子节点通过指针串成了有序链表,天然支持范围查询,比如WHERE age > 18 AND age < 30这种条件,找到起点之后沿着链表往后扫就行。

不过索引不是建得越多越好。每建一个索引,写入数据时就要多维护一棵B+树,插入、更新、删除的性能都会受影响。这就是为什么有的表写入慢,查了一下发现上面挂了十几个索引。所以索引设计的原则是:优先覆盖核心查询路径,数量克制,能用联合索引解决的就别建多个单列索引。

1.2 怎么判断索引有没有生效

大部分数据库都支持查看执行计划。MySQL里就是EXPLAIN,用法很简单:

EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 1;

看执行计划的时候重点看几个字段:

  • type:从好到差依次是constrefrangeindexALL。如果看到ALL,说明在扫全表,这就是最直接的报警信号。
  • key:实际用到的索引名。如果为NULL,说明没走任何索引。
  • rows:预估扫描的行数。这个数字越大,查询通常越慢。
  • Extra:如果出现Using filesort或者Using temporary,说明排序或去重用到了临时文件或临时表,这种往往有优化空间。

我这里有个真实案例。一张订单表有200万行数据,业务方反馈按用户查订单特别慢,要两三秒。用EXPLAIN一看,typeALL,扫描行数100多万。表上其实有user_id的索引,但查询条件里还带了一个status字段的等值条件,加上原有的索引区分度不够,优化器觉得不如直接全扫。后来把索引改成了联合索引(user_id, status),把两个条件都覆盖进去,查询时间直接从2000多毫秒降到了30毫秒。

1.3 几个实战中常见的索引失效场景

即使表上有索引,也不代表查询就一定会走。以下几种情况是我工作中反复遇到的,也是排查时优先要检查的:

  • 对索引列做了函数操作,比如WHERE DATE(create_time) = '2025-01-01',索引就失效了。正确写法是WHERE create_time >= '2025-01-01' AND create_time < '2025-01-02'
  • 隐式类型转换。user_id是varchar类型,查询时传了数字123,MySQL会先把列转成数字再比较,索引就废了。
  • 联合索引不满足最左前缀原则。比如联合索引是(a, b, c),查询条件只要bc,索引无法命中。
  • LIKE '%关键词'这种前置通配符的模糊查询,索引也无法使用。只能在条件允许的情况下改成LIKE '关键词%',或者上全文索引。

注意:EXPLAIN看的是预估执行计划,实际执行中MySQL会根据统计信息和实际情况调整。如果发现预估和实际差别很大,可以试试ANALYZE TABLE更新一下统计信息,再回头看执行计划。

2. SQL语句改写:不花一分钱配置的性能提升

有些慢查询,问题不在索引,而在SQL本身的写法上。同一句查询,用不同的写法,性能差距可能有一个数量级。SQL改写是最便宜的优化手段,不需要加硬件、不需要改架构,改一行代码就见效。

2.1 常见的SQL性能杀手

第一个是SELECT *。这不仅是多返回了几个字段的问题,更关键的是,如果表上有覆盖索引,SELECT *会让覆盖索引失效,因为索引里不可能包含所有列,数据库必须回表去查完整行数据。回表意味着额外的磁盘IO,数据量大时性能影响很明显。

第二个是深分页。很多后台管理系统的列表页习惯这么写:

SELECT * FROM orders ORDER BY id LIMIT 100000, 20;

这种写法的性能问题在于,数据库需要先扫描并丢弃前10万行,再取后面的20行。数据往后翻得越深,查询越慢。一个常见的优化手段是延迟关联,或者叫游标分页:

SELECT * FROM orders WHERE id > 100000 ORDER BY id LIMIT 20;

前提是业务上能接受用id作为分页游标。对于“上一页最后一条记录的id”这种交互方式,这个写法几乎是无损优化。

第三个是子查询和JOIN的滥用。有些场景下,子查询可以被改写成JOIN,或者反过来。关键是要看执行计划,不能凭感觉。MySQL的优化器对不同的写法可能有不同的处理方式,同一句逻辑,写法不同,执行路径可能截然不同。

2.2 改写SQL的一个完整实例

我之前处理过一个报表查询,业务方需要统计每个分类下的商品数量和销售额。原始的SQL用了三层嵌套子查询,跑了接近10秒。我做了两步改写:

第一步,把三层的子查询拆开看每一层的执行计划,确定哪一层是最耗时的。第二步,把最内层的子查询改写成JOIN+GROUP BY,并给关联字段建上索引。

改写后的SQL大概长这样:

SELECT c.category_name, COUNT(p.id), SUM(p.price) FROM categories c LEFT JOIN products p ON p.category_id = c.id GROUP BY c.category_name;

执行时间从10秒降到了0.5秒。这个案例给我的启发是:SQL改写不是靠背所谓的“优化技巧”,而是要看懂执行计划,找出真正卡脖子的那一层,然后对症下药。

2.3 改写SQL的实操建议

日常开发中,我建议养成几个习惯:

写完SQL先EXPLAIN一下,养成扫一眼执行计划的习惯。 尽量不要在循环里查数据库。比如查一个订单列表,再循环查每个订单的明细,这种N+1查询问题,要么用JOIN一把梭查出来,要么先查列表再批量查明细,在内存里做关联。 对OR条件谨慎处理。如果OR连接的是两个不同的索引列,优化器很可能不走索引,改成UNION ALL或者用IN代替,有时会好很多。

3. 表结构设计:调优的胜负手在源头

很多性能问题其实在设计表结构的时候就已经注定了。索引和SQL改写是在已经建好的表上做修补,而表结构设计是从源头决定了一整套系统的性能基线和扩展空间。

3.1 字段类型的选择直接决定存储和查询成本

我见过很多表设计得过于“随意”,该用整型的用字符串,该用datetime的用varchar,结果不仅浪费存储空间,查询性能也受影响。

几个常见的原则:

  • 能用数值类型就不用字符串,数值比较比字符串比较快得多。
  • 整数类型够用就用小的。TINYINT能存下的状态值,没必要用INT,更没必要用BIGINT
  • 字符串类型要控制长度。VARCHAR(255)VARCHAR(5000)即便存的内容一样短,但在排序和临时表操作时的开销是不一样的。
  • 避免使用TEXTBLOB这类大字段存储到业务主表里,如果必须存,建议拆到独立的扩展表,按主键一对一关联。

3.2 范式和反范式的平衡

教科书里强调三范式,但在实际业务中,过度规范化反而会带来性能问题。举个例子,订单表如果严格要求范式,那么订单里的商品名称、单价都得通过商品ID去关联查询,每次展示订单列表都要做多次JOIN

实际项目中,为了查询性能,在订单表里冗余一个product_name字段,或者把订单总额冗余到订单表里,这些都是典型的反范式设计。代价是需要维护数据一致性,但换来的查询性能提升往往非常可观。我的经验是:核心交易链路可以偏范式化保证一致性和灵活性,查询展示链路可以偏反范式化,牺牲一部分写操作复杂度,换取读操作的高性能。

3.3 字符集和排序规则必须统一

这是一个容易被忽略的坑。如果多张表用了不同的字符集,JOIN的时候数据库需要对字段做字符集转换,索引也会失效。我曾经排查过一个慢查询,两张表关联字段的字符集一个是utf8mb4,一个是latin1,执行计划直接显示全表扫描。后来把字符集统一成utf8mb4,问题立刻解决。

还有一点,主键设计尽量不要用随机字符串。用自增ID或者雪花算法生成的趋势递增ID,对InnoDB这种聚簇索引表来说,写入时能减少页分裂,顺序IO的效率远高于随机IO。

4. 参数配置调优:花最少的力气撬动最大的性能

有时候SQL没问题、索引也建了、表结构也合理,但数据库整体还是慢。这时候问题往往出在数据库实例的配置参数上。MySQL的默认配置是偏保守的,因为它要在各种机器上都能跑起来,但生产环境的机器资源通常远好于默认配置的预期。

4.1 最重要的几个InnoDB参数

InnoDB是MySQL默认的存储引擎,它的参数对性能影响最大。

第一个是innodb_buffer_pool_size,这是InnoDB的缓存池,用来缓存数据页和索引页。这个值设小了,数据大部分都在磁盘上,每次查询都要读磁盘,性能自然上不去。业界一个常见的建议是设为服务器物理内存的60%到70%,但前提是这台机器只跑数据库。如果机器上还部署了其他服务,就要适当调低,避免内存不够触发swap。

第二个是innodb_log_file_size,也就是redo log的文件大小。这个参数决定了对写操作的缓冲能力。设置太小,日志文件频繁切换,会导致频繁的磁盘刷写。但也不是越大越好,因为崩溃恢复时需要重放日志,文件太大恢复时间会变长。通常建议单个文件大小设为1GB到4GB之间,配合innodb_log_files_in_group使用。

第三个是innodb_flush_log_at_trx_commit。这个参数控制事务提交时多久刷一次redo log到磁盘。默认值是1,安全性最高,每次提交都刷盘,但性能也最差。如果能容忍极端情况下丢失最后一秒左右的数据,可以设为2,性能提升非常明显。

4.2 连接数相关的配置

max_connections是很多人喜欢乱调的参数。一看到“Too many connections”报错,就把它从200调到5000。这其实是个治标不治本的办法。每个连接都要占用线程栈、缓冲区等内存资源,连接数开得越大,每个连接能分到的资源反而越少,性能可能更差。

真正要做的是两件事:第一,合理评估应用的并发量,设置一个够用且有余量的值;第二,在应用层面用连接池,而不是每次请求都新建连接。连接池本身也有参数要调,后面第9个角度我会专门讲。

4.3 慢查询日志怎么开

调优的第一步是知道慢在哪,最直接的办法就是打开慢查询日志:

SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1;

long_query_time的单位是秒,设成1就表示超过1秒的查询会被记录下来。注意这里有个坑:long_query_time的默认值是10秒,很多新人都不知道,导致日志里什么都查不到,以为没有慢查询,其实只是阈值太高了。

上线阶段可以临时把阈值设低一点,比如0.5秒甚至0.1秒,然后把慢查询日志关掉或者设置日志轮转,避免日志文件无限膨胀把磁盘写满。

5. 缓存层介入:让数据库少干点活

不管是索引、SQL改写还是参数调优,本质上都是让数据库把同样的活干得更快。但还有一个更偷懒的思路:能不能让数据库干脆少干活?这就是缓存层存在的意义。

5.1 多级缓存的整体思路

以我做过的一个电商系统为例,完整的缓存链路大概是这个样子的:

浏览器端有HTTP缓存,CDN有边缘节点缓存,应用层有本地缓存(比如JVM的Caffeine),再往外是一层Redis分布式缓存,最后才落到数据库。每一层缓存命中不了,才往下一层查。这样设计的好处是,数据库实际承受的请求量可能只有总请求量的百分之一都不到。

5.2 缓存的三个经典问题

用缓存绕不开三个问题,面试和实战都经常碰到:

缓存穿透。查询一个不存在的key,缓存里没有,数据库里也没有,每次请求都直接打到数据库。如果一个恶意攻击者疯狂请求不存在的商品ID,数据库压力会很大。解决办法是缓存空结果,并设置较短的过期时间,或者用布隆过滤器先过滤掉一定不存在的key。

缓存击穿。某一个热点key在过期的瞬间,大量请求同时打到数据库。解决办法是加互斥锁,或者把热点key的过期时间设为永不过期,后台异步更新。

缓存雪崩。大量key在同一时间过期,导致请求都落到数据库上。解决办法是给过期时间加一个随机值,让过期时间分散开,或者做多级缓存。

5.3 缓存与数据库的数据一致性

这是一个很多人纠结的点。最稳妥的方案是Cache Aside模式:读的时候先读缓存,读不到就读数据库再回填缓存;写的时候先更新数据库,再删缓存。为什么是“删缓存”而不是“更新缓存”?因为更新缓存要考虑并发写的问题,两个请求同时更新数据,后更新的缓存值可能不是最终值;而删除缓存的话,下次读的时候自然会从数据库拉到最新值。

当然,删除缓存也有极端情况下的一致性问题,但概率比较低。如果对一致性要求极高,可以考虑引入消息队列,在数据库更新后发送消息,由消费者异步删除缓存。在绝大多数业务场景下,Cache Aside加上合理的过期时间已经够用了。

6. 分区表与分库分表:数据量大到单表扛不住时

当单表的数据量增长到一定程度,不管怎么加索引、改SQL,性能都会遇到瓶颈。这个时候就需要从“怎么让查询更快”转向“怎么让要查的数据更少”。分区和分表就是为了解决这个问题。

6.1 什么时候需要分区

MySQL的分区表是把一张逻辑表拆成多个物理存储分区,但对应用来说还是一张表。常见的分区方式有RANGE分区、LIST分区、HASH分区和KEY分区。

一个典型场景是按时间分区。日志表、订单表这类有明确时间维度的数据,可以按月分区。查询时如果条件里带了分区字段,优化器会自动做分区裁剪,只扫描需要的那几个分区,数据量直接减少一个数量级。

分区也不是没有代价。如果查询条件里没有带分区字段,那么所有分区都会被扫描,性能可能比不分区的表还差。所以分区表的设计原则是:业务查询必须高频使用到分区字段作为筛选条件。

6.2 分库分表的关键决策

分区解决不了写入能力的瓶颈,当单库的写入TPS到了上限,或者单表数据量到了几千万上亿,就需要考虑分库分表了。

分库分表最常见的是水平拆分,也就是按某个字段(通常是用户ID或订单ID)的哈希值,把数据分散到多张结构相同的表里。比如user_id % 16,就可以均匀分到16张表。这里的关键是拆分键的选择,因为它决定了后续所有查询的路径。

如果拆分键是用户ID,那么所有按用户ID查的请求都可以直接路由到对应的分表,速度非常快。但如果业务上经常按订单ID查,而订单ID跟用户ID没有直接关联,那这个查询就得在所有分表上各查一遍,再汇总结果,复杂度会高很多。

我的建议是:分库分表是最后的方案,因为它带来的不仅仅是技术复杂度,还有跨分片的事务问题、全局唯一主键问题、排序分页问题、多表关联问题。这些问题每一个都不是省油的灯。能晚点拆就晚点拆,能用缓存、分区表、归档历史数据等手段拖延扩容时间就尽量拖延。

6.3 冷热数据分离

在真正走上分库分表这条路之前,还有一个性价比极高的中间方案——冷热数据分离。把一年前的订单迁移到历史订单表,或者直接用归档工具定期把数据导出到单独的归档库。业务上大部分的在线查询都是查近期数据,把冷数据挪走后,热表的体量立刻降下来,索引效率明显回升,这个方案实施起来比分库分表简单得多,而且效果好。

7. 监控告警与性能分析:没有数据支撑的调优都是耍流氓

前面讲的都是具体的优化手段,但调优不能靠拍脑袋。你得知道系统当前的状态是什么样的,瓶颈到底在哪,优化之后效果如何,这些都需要监控数据来做支撑。我见过不少团队,一上来就调参数、改SQL,结果改完性能没有变化,甚至更差了,就是因为缺少一个完整的性能基线来对比。

7.1 监控哪些核心指标

数据库监控至少要覆盖以下几类指标:

  • 性能类:QPS、TPS、查询响应时间、慢查询数量、锁等待时间。
  • 资源类:CPU使用率、内存使用率、磁盘IO的读写延迟和吞吐量、网络带宽。
  • 连接类:当前连接数、活跃连接数、连接拒绝率。
  • InnoDB引擎层:缓冲池命中率、日志文件写入频率、行锁等待次数、死锁次数。
  • 主从复制类:复制延迟时间、从库的IO和SQL线程状态。

这些指标可以用Prometheus加上Grafana这套开源方案来采集和展示。数据库领域常用的exporter有mysqld_exporter,直接暴露Metrics接口,配置简单,效果很好。

7.2 用慢查询日志做性能分析

除了实时监控,慢查询日志是最重要的离线分析素材。前面提过开启慢查询日志的方法,但真正要分析的时候,不能光靠人眼去看。日志量一大,需要工具来辅助分析。

MySQL自带的mysqldumpslow工具可以按执行次数、耗时等维度汇总慢查询:

mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.log

这个命令的意思是把慢查询日志按平均耗时排序,显示前10条。这是最快定位问题SQL的方式。另外还有一个工具叫pt-query-digest,是Percona Toolkit里的一员,分析功能更强大,能给出每条SQL的响应时间分布、占比等,适合做深度分析。

7.3 全链路监控的重要性

最后说一句,只盯着数据库本身的监控是不够的。一个查询慢,可能是数据库慢,也可能是应用服务器的线程被堵塞了,也可能是网络延迟高,甚至可能是前端加载慢导致接口整体响应时间长。有条件的话,尽量搭建全链路的监控体系,从浏览器、网关、应用到数据库,每一层的耗时都要能看到。这样定位问题的时候才能快速判断慢的环节在哪里,而不是一上来就在数据库里折腾半天。

8. 主从复制与读写分离:扛住读多写少的流量

单台数据库的性能再高也有天花板。当读流量远超写流量,比如典型的读多写少的互联网业务,一个非常有效的架构手段就是搭建主从复制,做读写分离。

8.1 主从复制的基本原理

MySQL主从复制基于binlog实现。主库上所有写操作都会记录到binlog中,从库通过IO线程拉取binlog并写入到自己的中继日志(relay log),再由SQL线程把中继日志里的操作在从库上重放一遍,从而保持主从数据一致。

复制的模式主要有两种。传统的是异步复制,主库提交事务后不等待从库响应,性能最好,但有数据丢失的风险,主库挂了之后,从库可能少了最后一部分数据。另一种是半同步复制,主库提交事务后至少等待一个从库确认接收到binlog,才返回给客户端。安全性高了不少,代价是性能略有损耗。

8.2 读写分离的落地方式

架构上,应用层的读写分离一般有两种实现路径。一种是在代码层面做数据源的路由,比如Spring框架里配置两个数据源,写操作走主库,读操作走从库。另一种是接入中间件,比如ProxySQL、Mycat、ShardingSphere这类数据库代理,应用只管连代理,代理负责把读写请求分发到主库和从库。

我个人的经验是,刚开始流量不大的时候,用代码层面做路由就够了,额外引入中间件会增加架构复杂度。等到团队规模大了、业务复杂了,再用中间件做统一管控也不迟。

8.3 复制延迟是必须面对的坑

读写分离最大的坑是复制延迟。主库刚写入一条数据,从库还没来得及同步,这时候读请求发了过去,读到的是旧数据。这在一些实时性要求高的场景下是没法接受的。

应对复制延迟的办法,最常见的是强制部分读走主库。比如用户下单后立刻跳转到订单详情页,这个订单详情的读请求强制走主库,因为刚写完的数据大概率还没同步到从库。另一个办法是把从库的parallel_workers调大,提升从库应用binlog的并行度,从源头降低延迟。

还有一个排查方向:如果从库延迟一直很大,先看是不是有长时间运行的查询在从库上执行,导致SQL线程被卡住了。这种情况在从库上跑大报表任务的时候非常常见。

9. 连接与线程池调优:细节里的性能黑洞

数据库的每一次连接都不是免费的。建立连接要经过TCP握手、身份验证、分配线程栈等一堆步骤,开销相当可观。高并发场景下,连接管理做得好不好,对性能的影响非常直接。

9.1 应用层的连接池怎么配

以Java应用最常见的HikariCP为例,它是个性能很好的连接池,但拒绝服务式的默认配置其实不适合所有场景。连接池的核心参数是maximumPoolSizeminimumIdle

maximumPoolSize不是越大越好。每个连接背后,数据库都要消耗内存和线程资源。连接过多反而会让数据库忙于上下文切换,响应变慢。一个经验值是:core线程数 * (1 + 等待时间 / 处理时间)。当然这只是估算公式,实际还是要压测验证。

我见过一个典型的案例:某服务把连接池最大连接数配到了200,数据库最大连接数才300,多个服务实例连同一个数据库,稍微一扩容,数据库连接数直接打满,所有请求超时。这是个非常经典的教训——连接池的配置必须结合数据库侧的总连接数做整体规划,不能只盯着单个应用看。

9.2 数据库侧的连接参数

MySQL这边也有几个跟连接相关的参数值得关注。

wait_timeoutinteractive_timeout控制空闲连接的超时时间。设置太短,连接容易被断开,应用就要报错重连;设置太长,大量空闲连接占着资源不释放。通常建议设置在60秒到300秒之间,配合连接池的心跳检测一起用。

thread_cache_size控制线程缓存。如果应用频繁创建和销毁连接,这个值配大一些可以减少线程创建的消耗。

9.3 连接池预热

还有一个容易被忽视的点是连接池预热。服务刚启动的时候,连接池是空的,前几个请求都要现建连接,响应时间会明显偏慢。如果对初始化时间敏感,可以在应用启动完成后主动执行几条简单的SQL,把连接池填满。这个操作虽然简单,但实测对降低冷启动时的请求延迟非常有效。

10. 锁竞争与事务并发:别让数据库内耗拖垮性能

最后一个角度是数据库自身的并发控制能力。如果锁用不好,数据库的资源都耗在处理锁等待和死锁上了,真正的业务查询反而得不到资源。这个角度在并发量上来之后,会变得越来越重要。

10.1 InnoDB的锁机制要点

InnoDB支持行级锁,这是它能支撑高并发的重要前提。但行锁也分几种:记录锁锁的是具体的索引记录,间隙锁锁的是两条记录之间的区间,防止幻读。间隙锁是InnoDB在RR(可重复读)隔离级别下解决幻读问题的重要手段,但也容易导致锁范围扩大。

一个很常见的锁竞争场景是这样的:事务A更新了id IN (1, 2, 3)的三行数据,还没提交;事务B也想更新id IN (3, 4, 5)的数据,其中id=3这行被A锁住了,B只能等待A提交或回滚。如果A持有锁的时间太长,B的等待时间就会很长,表现在业务上就是大量的请求超时。

10.2 从哪些角度减少锁冲突

一是让事务尽快提交。事务里不要做RPC调用、外部API请求这类耗时操作,避免长时间持锁。二是尽量用等值条件去更新,减少间隙锁的范围。三是控制事务的规模,一次更新几千上万行,不如拆成小批量提交,减少单次锁的持有时间。

死锁是另一个让人头皮发麻的问题。虽然死锁本身不可避免,但可以通过观察死锁日志定位原因。MySQL里查看最近一次死锁信息:

SHOW ENGINE INNODB STATUS;

重点看LATEST DETECTED DEADLOCK这一段,里面会列出两个事务分别持有和等待哪些锁。绝大多数死锁都有一个模式:两个事务加锁的顺序不一致。比如事务A先锁表1再锁表2,事务B先锁表2再锁表1,那就非常容易死锁。解决办法就是统一加锁顺序,让所有事务都按照同样的顺序获取锁。

10.3 隔离级别的选择

隔离级别越高,数据库需要做的并发控制就越多,性能越低。默认的RR级别能避免幻读,但间隙锁的范围更大,锁竞争也更激烈。如果业务上能接受读已提交(RC)级别,并发性能通常会好不少。MySQL官方在复制场景下也推荐使用RC,因为RC级别下binlog的格式可以更简单。很多互联网公司都会在业务允许的情况下,把隔离级别从RR改到RC,换来更低的锁竞争和更高的并发吞吐。

选择哪个隔离级别,需要业务方和技术方一起权衡一致性和并发性的平衡点。没有统一答案,只有基于业务场景的选择。


讲到这里,10个角度算是全部过了一遍。最后说一点我的个人体会:调优不是一锤子买卖,而是持续迭代的过程。每做一个优化,都要用监控数据去验证效果,看看QPS和响应时间是不是真的变好了,有没有引入新的问题。我也见过有人为了调优而调优,把一堆参数改得很激进,结果系统崩了,再改回来。这种折腾没有任何意义。

如果你看完这篇文章,不知道从哪里下手,我建议你先做两件事:第一,打开慢查询日志,把慢SQL捞出来;第二,用EXPLAIN看看这些慢SQL的执行计划。90%的情况下,看完这两个东西,下一步该做什么就清楚了。剩下的,就是按这套框架逐个排查,把优化当成体检一样定期做一遍。等你把前面这几个最容易见效的角度都过完了,你对数据库的理解,一定会比现在深一个层次。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询