面试官灵魂拷问:为什么 SQL 语句不要过多的 join?
JOIN最大的问题不在于它本身慢而在于高并发场景下它会把整个系统拖垮。JOIN为什么会变慢MySQL执行JOIN的底层算法是 Nested Loop Join嵌套循环连接。简单说就是拿表A的每一行去表B里找匹配的行。两张表JOIN复杂度是 M x N。三张表就是 M x N x K。表越多数据量越大执行时间不是线性增长而是乘法级别地膨胀。一条单表查询可能5ms就返回了加几个JOIN之后轻松飙到200ms甚至更久。在低并发环境下200ms也能接受用户感知不明显。但问题出在高并发的时候。高并发下的连锁反应数据库连接池的连接数是有限的一般业务系统配置在50~200之间。正常情况下一条SQL 5ms执行完就把连接还回池子连接周转很快池子永远有余量。但多表JOIN的慢SQL一旦出现情况就变了一条SQL执行500ms连接被占住500ms才归还同一时间涌入大量请求每个都要占一条连接连接池很快被占满新来的请求只能排队等待排队的请求越积越多接口响应时间从毫秒级飙到秒级上游调用方开始超时触发重试流量进一步放大最终连接池彻底耗尽系统雪崩这就是典型的慢SQL引发的雪崩链路。多表JOIN不是唯一的慢SQL来源但它是最常见的那个。一张图就能看明白左边的简单查询5ms归还连接池子永远健康。右边的多表JOIN占住连接500ms高并发一来池子瞬间被打满后续请求全部排队。怎么替代多表JOIN核心思路就是把JOIN拆成多次单表查询在应用层组装数据。// 先查订单 ListOrder orders orderMapper.selectByUserId(userId); // 拿到商品ID列表批量查商品 ListLong productIds orders.stream() .map(Order::getProductId) .toList(); ListProduct products productMapper.selectBatchIds(productIds); // 在内存里组装 MapLong, Product productMap products.stream() .collect(Collectors.toMap(Product::getId, Function.identity()));两次单表查询每次都走索引加起来可能10ms搞定。比一条三表JOIN快得多而且对连接池几乎没有压力。其他常见方案对高频查询场景做冗余字段避免关联查询。或者用宽表把多表数据提前聚合好查询时直接读宽表。这些方案的共同思路就一个减少单条SQL的执行时间让数据库连接尽快归还在高并发下保持连接池的健康周转。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2548482.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!