Explorar o código

perf: 订单列表查询优化 — 消除 fillOrderLabels 中的 N+1 查询

fillOrderLabels 在逐条填充订单标签时,对每条订单单独执行:
- deviceMapper.selectByDeviceId() — 每订单 1 次 SQL
- shopMapper.selectById() — 历史订单未写 shopId 时再 1 次

改为循环前批量查询所有设备和门店,构建 Map,循环内从 Map 取值。
10 条/页从最多 20 次额外 SQL 降为固定的 2 次批量查询。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline hai 1 semana
pai
achega
23dd0844fe

+ 41 - 15
haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java

@@ -554,7 +554,36 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
             }
         }
 
-        // 3. 逐条填充标签
+        // 3. 批量查询设备信息,避免循环内逐条查询(N+1)
+        List<String> deviceIds = orders.stream()
+                .map(Order::getDeviceId)
+                .filter(id -> id != null && !id.isEmpty())
+                .distinct()
+                .collect(Collectors.toList());
+        Map<String, Device> deviceMap = new HashMap<>();
+        if (!deviceIds.isEmpty()) {
+            List<Device> devices = deviceMapper.selectList(
+                    new LambdaQueryWrapper<Device>().in(Device::getDeviceId, deviceIds));
+            if (devices != null) {
+                deviceMap = devices.stream().collect(Collectors.toMap(Device::getDeviceId, d -> d, (a, b) -> a));
+            }
+        }
+
+        // 4. 批量查询门店信息(用于历史订单未写入 shopId 时回退查询)
+        Map<Long, Shop> shopMap = new HashMap<>();
+        List<Long> shopIds = deviceMap.values().stream()
+                .map(Device::getShopId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (!shopIds.isEmpty()) {
+            List<Shop> shops = shopMapper.selectBatchIds(shopIds);
+            if (shops != null) {
+                shopMap = shops.stream().collect(Collectors.toMap(Shop::getId, s -> s, (a, b) -> a));
+            }
+        }
+
+        // 5. 逐条填充标签(使用预加载的 Map,无额外 SQL)
         for (Order order : orders) {
             // 用户消费标签 + 手机号
             if (order.getUserId() != null) {
@@ -595,23 +624,20 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
                 }
             }
 
-            // 补充设备名称;历史订单未写入门店信息时,回退到 device→shop 查询
+            // 补充设备/门店名称(从预加载的Map取值,无额外SQL)
             if (order.getDeviceId() != null && !order.getDeviceId().isEmpty()) {
-                try {
-                    Device device = deviceMapper.selectByDeviceId(order.getDeviceId());
-                    if (device != null) {
-                        order.setDeviceName(device.getName());
-                        if (order.getShopId() == null && device.getShopId() != null) {
-                            order.setShopId(device.getShopId());
-                            Shop shop = shopMapper.selectById(device.getShopId());
-                            if (shop != null) {
-                                order.setShopName(shop.getName());
-                                order.setStoreName(shop.getName());
-                            }
+                Device device = deviceMap.get(order.getDeviceId());
+                if (device != null) {
+                    order.setDeviceName(device.getName());
+                    // 历史订单未写入门店信息时,回退到 device→shop
+                    if (order.getShopId() == null && device.getShopId() != null) {
+                        order.setShopId(device.getShopId());
+                        Shop shop = shopMap.get(device.getShopId());
+                        if (shop != null) {
+                            order.setShopName(shop.getName());
+                            order.setStoreName(shop.getName());
                         }
                     }
-                } catch (Exception e) {
-                    log.warn("获取订单关联门店信息失败: orderId={}, deviceId={}", order.getId(), order.getDeviceId(), e);
                 }
             }
         }