2026年2月12日,晚上六点多的时候,刚刚把线上的一个慢SQL日志给翻完了,我感觉到眼睛疼。
又是因为缓存放不下,磁盘在那嘎吱嘎吱读。
其实不想拆库的。
确实是这样,一旦想到当那些分布式事务被拆解完之后,以及跨库join的情况,还有运维人员在半夜打电话过来询问你“主键冲突了要怎么去处理”,就会让人感觉到头皮一阵发麻。
然而毫无办法,数据量不顾一切地疯长,恰似春季庭院之中的杂草,你于昨日刚剔除完此批,至今日彼批又迅猛冒尖。
磁盘读IO瓶颈怎么办
有着太多的热点数据,buffer pool的大小却仅仅只有那么一点儿,恰似那快挤爆的像早高峰时候的地铁。
你明明清楚这行数据处于磁盘的某个扇区之中,然而却无法触及,必须排队等候。
最气的是,有些字段压根不怎么查,却占着整行的缓存坑位。
扔长文本,扔备注,扔 JSON 配置于扩展表。主表仅留订单号,仅留用户 ID,仅留状态,仅留金额。一页数据可多塞几十行,缓存命中率肉眼可见地回升了。
别用join。我知道你手痒,但忍一下。
在业务层面,首先去查询主表,进而获取到ID列表,接着通过in操作去查询扩展表,代码层面虽说显得有些啰嗦,然而数据库却呈现出了满意的状态。
SQL里塞满join、group by、order by
见过那种一个SQL写四五十行的吗。
还全表扫描。
索引都没用对,还怪数据库慢。
建立合适的索引有那么难吗
组合索引的顺序搞反了,选择性高的列放后面,等于白建。
更别提那些给日期字段加上函数的,就是那种,where date(create_time) = ‘2026-02-12’ 这种情况。
索引失效,全表扫描,CPU瞬间飘红。
你倒是省事了,数据库快被你逼疯了。
把计算的逻辑,向外进行挪动,在业务层进行计算,由缓存层来承担,不要什么都一股脑儿地塞给数据库这个老实巴交的角色,使其不堪重负。
单表几千万行还在硬扛
水平分表其实没想象中那么可怕。
按用户ID哈希一下,拆成16张表。
每一张表之中,存在着几百万行的数据,索引的深度,从原本的4层降低到了3层,如此一来,执行计划看起来都变得舒展了许多。
不过分表键一定要选对。
90%的查询都带上这个字段,你才能享受分片带来的红利。
要是没带该怎么进行查询呢,是采用映射表的方式、基因法的方式或者——说实话——直接将其怼到ES宽表当中去吗。
分都分了,就别指望一个筐装天下。
非热点字段拖累整张表
垂直分表这事,最适合那种“表里啥都有”的设计。
有一个用于存放用户相关信息的表,其中存着手机号,还有昵称,另外还存了身份证照片以 base64 形式呈现的数据,以及最后一次登录时的 IP 归属地,并且还有用户所撰写的长达三千字的自我介绍。
数据行的宽度,如同高速公路那般宽阔,在数据库里,一页之中读不出几行数据,热点数据反倒被排挤出去了。
把活跃字段留在主表,不常用的、大字段的,扔给扩展表。
这样扫描效率翻倍,IO压力也下来了。
分页排序怎么变慢了
分页查询的噩梦通常发生在排序字段不是分片键的时候。
你要从十六个分片里头,各自取出前面的一百条,接着在内存当中进行归并排序,随后再取出前面的一百条。
内存消耗、网络开销,都比单库单表复杂得多。
非分片键排序为什么更慢
要么去接纳这个代价,要么致使业务侧作出妥协,即默认仅仅查询最近三个月的数据,且默认按照分片键进行排序。
有时候,技术解决不了的问题,需求可以。
跨库事务到底怎么办
两阶段提交,XA协议。
听起来很标准,用起来很沉重。
协调节点一挂,所有参与者都得等,锁释放不了,业务直接卡死。
所以现在大家学聪明了。
若无必要,请勿跨库。于设计分片键之际,尽可能将那些要求严苛一致性的数据放置于同一分片之内。
实在不行,上Seata这种分布式事务框架。
但心里得清楚,一致性是有代价的。
到底拆还是不拆
有个原则我贴在工位挡板上了:
能不分尽量不分。
先试试升级硬件、读写分离、索引优化、冷热归档。
诸多被谓之“大数据量”者,实则唯慢查询为之作祟罢了,索引构建得当,问题便消解大半矣。
真的走到分库分表这一步,也不是终点。
只是换了一个更复杂的环境,继续面对那些永恒的命题。
数据一致性、查询效率、运维成本。
没有银弹,只有权衡。
窗户外天已经黑透了。
咖啡凉了,但线上那个订单库终于稳住了。
下周还得盘一下日志表,那玩意儿也快两亿行了。
啧,又是分表。
不过那是下周的事。
今晚,先回家。

Comments NOTHING