判断“接口慢”是不是由服务与云数据库之间的链路造成,关键不是先猜网络,而是先把数据库执行时间与链路额外耗时拆开测。
核心判断
这类问题最容易被一句“云数据库慢”带偏,但真正需要回答的是:慢在数据库执行,还是慢在服务与数据库之间的往返、建连、连接池等待与结果传输。
如果不拆开看,接口总耗时只是一个混合值,无法判断瓶颈所在。
一个实用的拆分方式是:
接口总耗时 = 排队 + 取连接 + TCP/TLS 建连 + SQL 往返 + 数据库执行 + 结果传输 + 应用层处理
最小可行测量方案
1. 测冷连接耗时
在服务实际运行的机器或 Pod 内,每次新建一个数据库连接,只执行一次 SELECT 1,连续测 50 到 200 次,记录 p50、p95、p99。
这组数据主要用来观察:
- DNS 解析是否偏慢;
- TCP 或 TLS 握手是否偏慢;
- 是否存在数据库代理、NAT、私网网关或跨可用区带来的额外路径成本;
- 应用是否根本没有稳定复用连接。
如果冷连接慢、热连接快,优先怀疑建连链路与连接管理,而不是 SQL 本身。
2. 测热连接单次往返耗时
复用同一个已建立的连接,连续执行很多次 SELECT 1。
这组数据更接近“纯协议往返 + 少量驱动开销”。如果这一步已经明显偏高,才更有理由怀疑服务到数据库之间的网络路径本身有问题。
3. 同时记录客户端耗时与数据库执行耗时
对真实业务 SQL,至少保留两组时间:
- 应用侧 SQL 总耗时:从驱动发起到结果读回;
- 数据库侧执行耗时:数据库内部实际执行该语句花的时间。
最有判断力的对照是:
- 应用侧明显慢于数据库侧:优先排查链路往返、结果集过大、驱动反序列化、连接池等待,或一次请求触发了过多 SQL;
- 应用侧与数据库侧都慢:优先看执行计划、索引设计与扫描范围。
4. 统计一次接口到底发了多少条 SQL
如果一个接口在 ORM 或仓储层里悄悄发了很多条 SQL,即使单次往返不高,总耗时也会被线性叠加。
这类问题经常表现为:同集群自建数据库时还勉强可接受,一旦换成托管云数据库,额外几毫秒 RTT 被放大后,接口体感突然明显变差。
建议直接采集的指标
为了让判断不再靠猜,应用侧至少应增加这些指标:
db_pool_wait_ms:等待连接池分配连接的时间;db_connect_ms:新建连接的时间;db_query_client_ms:应用看到的单条 SQL 总耗时;db_query_server_ms:数据库内部执行耗时;db_rows_returned:返回行数;sql_count_per_request:单个接口触发的 SQL 数量。
有了这组数据,通常就能快速回答“是网络问题,还是查询问题”。
判定模式
几个常见模式可以直接用来做初筛:
- 冷连接慢,热连接快:更像建连成本、TLS、DNS、代理链路或连接池配置问题;
SELECT 1热连接也慢:更像服务到数据库之间的往返本身偏高;- 数据库执行很快,但应用侧 SQL span 很慢:更像网络往返、结果传输、驱动处理,或单请求 SQL 次数过多;
- 数据库侧与应用侧都慢:更像执行计划、索引与扫描范围问题。
同集群自建库很快,换云数据库变慢时优先对比什么
如果“同集群自建数据库速度飞快,换成云数据库就慢”是稳定现象,优先对比这些条件是否一致:
- 是否仍在同地域、同可用区;
- 是否走私网而不是公网;
- 是否引入了数据库代理、PrivateLink、NAT 或额外网关;
- 是否启用了 TLS;
- 是否使用了相同的连接池策略;
- 是否数据库规格、IOPS、参数与执行计划一致;
- 是否真实返回数据量明显变大。
这一步的意义在于:不要把“托管数据库”当成单一变量。 很多体感上的“云数据库慢”,本质上是网络路径、连接管理与访问模式同时发生了变化。
一个排查顺序
如果要快速判断这是不是接口变慢的主因,可以按这个顺序:
- 在服务运行环境里测冷连接
SELECT 1; - 在同一连接里测热连接
SELECT 1; - 记录真实 SQL 的应用侧耗时与数据库侧耗时;
- 统计单个接口的 SQL 条数;
- 再回头检查慢 SQL 的执行计划与索引。
这样做的目的不是把网络与 SQL 对立起来,而是先确认:数据库是不是已经足够快,只是被链路和访问模式拖慢了最终接口。
来源:use-the-index-luke · use-the-index-luke-execution-plans · use-the-index-luke-the-where-clause
相关页面:sql-execution-plans · sql-indexing · query-shape-and-index-usage