前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何优雅的解决n 1查询!!!

如何优雅的解决n 1查询!!!

作者头像
林老师带你学编程
发布2019-10-24 17:11:34
1.3K0
发布2019-10-24 17:11:34
举报
文章被收录于专栏:强仔仔强仔仔

我们在写代码的时候非常忌讳出现n+1次查询,这就意味的你的循环有多少次,就会查询多少次数据库,这是很恐怖的场景。

因为每次服务调用mysql查询的时候,都是一件很耗费性能的操作,下面我们举个例子,来说说n+1的触发场景及解决方案。

业务需求

需要查询指定用户的订单详细信息,详细信息不仅仅包含订单本身的信息,还包含其它信息。这个时候童鞋们往往会采用,如下所示的方式进行数据获取。

代码语言:javascript
复制
 /**
* 订单mapper
*/
private OrderMapper orderMapper;

/**
* 订单商品mapper
*/
private OrderFeeMapper orderFeeMapper;

/**
* 查询用户id指定的所有订单列表信息
* @param userId
* @return
*/
public List<OrderDetail> getOrderDetailList(int userId) {
    // 查询订单列表数据
    List<Order> orderList = orderMapper.getOrders(userId);
    List<OrderDetail> orderDetailList = new ArrayList<>();
    for (Order order : orderList) {
        OrderDetail orderDetail =new OrderDetail();
        // 查询订单对应费用信息
        OrderFee orderFee = orderFeeMapper.getOrderFeeDetail(order.getOrderId());
        orderDetail.setOrderFee(orderFee);
        // 添加到集合中
        orderDetailList.add(orderDetail);
        }
    return orderDetailList;
}

如果这个用户订单量少还好,一旦这个用户订单量超级大,这个操作的响应时间将会非常长,长到你无法忍受的地步,那我们要怎么进行优化呢?

n+1改为1+1模式

我们可以将n次查询的条件添加到一个集合中,然后通过in语句一次性查询出我们需要的数据,这样就可以避免n+1次查询的出现,可以大大提高我们的执行效率,代码如下所示:

代码语言:javascript
复制
/**
* 订单mapper
*/
private OrderMapper orderMapper;

/**
* 订单商品mapper
*/
private OrderFeeMapper orderFeeMapper;

/**
* 查询用户id指定的所有订单列表信息
* @param userId
* @return
*/
public List<OrderDetail> getOrderDetailList(int userId) {
    // 查询订单列表数据
    List<Order> orderList = orderMapper.getOrders(userId);
    List<OrderDetail> orderDetailList = new ArrayList<>();
    List<String> orderIdList = new ArrayList<>();
    for (Order order : orderList) {
        OrderDetail orderDetail =new OrderDetail();
        // 添加订单到集合中
        orderIdList.add(order.getOrderId());
        // 添加到集合中
        orderDetailList.add(orderDetail);
    }
    List<OrderFee> orderFeeList = orderFeeMapper.getOrderFeeList(orderIdList);
    // 递归将orderFeeList中费用信息设置到对应订单的orderDetail对象中(具体代码省略)
    setOrderDetail(orderFeeList,orderDetailList);
    return orderDetailList;
}

连接查询失效场景

童鞋们可能会问为啥不采用mysql连接查询,一下子将相关表数据一起查询出来。这边主要出于如下考虑:

笛卡儿积

连接查询其实就是笛卡尔积的应用,一张表的查询操作可能会很快,但是多张表联查就会非常慢,因为他们的数据量是n*m,所以有时候采用连接查询,还不如分成多次查询来的快。

分库分表

如果系统的数据库采用的是分库分表,这个时候有些表是不能够进行连接查询,我们只能分多次查询,然后组装到一起。

数据来源不一致

如果订单的数据是从第三方接口获取的,那我们自然没办法进行连表查询。

总结

我们写代码的时候一定要特别注意n+1查询出现,循环体内要多检查几遍,是否有子查询的出现。

后记

童鞋们要记住,每一种模式都存在一定的缺陷,数据量不一样,模式的执行效率天差地别。童鞋们有空的话可以思考如下问题:

  1. n+1模式修改为1+1模式需要注意哪些问题?
  2. mysql中in语句长度是否有限制(或者说sql长度是否有限制,如果有那是多少)?
  3. n+1中如果n的数值非常大,要如何优化(因为直接查询组装成in,查询效率也会很差)?
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 业务需求
  • n+1改为1+1模式
  • 连接查询失效场景
  • 总结
  • 后记
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档