From fbce3ff8d28f55fdc8e7c6e446534dcfa181f488 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期三, 05 八月 2026 20:00:52 +0800
Subject: [PATCH] fix: 企业用户充电分析慢查询,改逆反查 + Service 层聚合(去跨分片 JOIN)

---
 ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml |  188 +++++++++++++++++-----------------------------
 1 files changed, 71 insertions(+), 117 deletions(-)

diff --git a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
index 85a5aff..b7148c7 100644
--- a/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
+++ b/ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -3019,137 +3019,91 @@
         ORDER BY b.site_id
     </select>
 
-    <sql id="enterpriseChargingBaseWhere">
-        toi.invoicing_object_type = 2
-        AND toi.status IN (2, 3)
-        AND tod.order_type = 1
+    <!--
+        企业用户充电分析 —— 逆反查聚合(原实现见 git:enterpriseChargingAnalysis 等把
+        t_order_invoice(10片/app_user_id) + t_order_invoice_detail(20片/order_invoice_id) +
+        t_charging_order(50片/app_user_id) 在代理层跨分片 JOIN,分片键不一致只能全量广播,无筛选必超时)。
+        这里只提供单表/按分片键 IN 路由的构建块,按公司聚合在 Service 层完成(与 enterpriseChargingDetail 同模式)。
+    -->
+
+    <!-- 企业发票行(t_order_invoice 单表 10 片,抬头级过滤可下推到各分片;id 唯一故无需 GROUP BY) -->
+    <select id="enterpriseInvoiceRows" resultType="com.ruoyi.order.dto.EnterpriseChargingAggRow$Invoice">
+        SELECT
+            id,
+            TRIM(name) AS companyName,
+            IFNULL(TRIM(tax_identification_number), '') AS socialCreditCode,
+            company_address AS companyAddress,
+            company_phone AS companyPhone,
+            IFNULL(total_amount, 0) AS totalAmount
+        FROM t_order_invoice
+        WHERE invoicing_object_type = 2
+          AND status IN (2, 3)
         <if test="data.exactCompanyName != null and data.exactCompanyName != ''">
-            AND TRIM(toi.name) = TRIM(#{data.exactCompanyName})
+            AND TRIM(name) = TRIM(#{data.exactCompanyName})
         </if>
         <if test="(data.exactCompanyName == null or data.exactCompanyName == '') and data.companyName != null and data.companyName != ''">
-            AND TRIM(toi.name) LIKE CONCAT('%', TRIM(#{data.companyName}), '%')
+            AND TRIM(name) LIKE CONCAT('%', TRIM(#{data.companyName}), '%')
         </if>
         <if test="data.socialCreditCode != null and data.socialCreditCode != ''">
-            AND IFNULL(TRIM(toi.tax_identification_number), '') = TRIM(#{data.socialCreditCode})
+            AND IFNULL(TRIM(tax_identification_number), '') = TRIM(#{data.socialCreditCode})
         </if>
-        <if test="data.siteType != null">
-            AND s.site_type = #{data.siteType}
-        </if>
-        <if test="data.partnerId != null">
-            AND s.partner_id = #{data.partnerId}
-        </if>
-        <if test="data.siteId != null">
-            AND co.site_id = #{data.siteId}
-        </if>
-        <if test="data.createTime1 != null">
-            AND co.create_time &gt;= #{data.createTime1}
-        </if>
-        <if test="data.createTime2 != null">
-            AND co.create_time &lt;= #{data.createTime2}
-        </if>
-    </sql>
+    </select>
 
-    <select id="enterpriseChargingAnalysis" resultType="com.ruoyi.order.dto.EnterpriseChargingAnalysisVO">
+    <!-- 企业发票充电明细(t_order_invoice_detail 按 order_invoice_id 分片,IN 直接路由;order_type=1 只取充电明细) -->
+    <select id="enterpriseInvoiceDetailRows" resultType="com.ruoyi.order.dto.EnterpriseChargingAggRow$Detail">
         SELECT
-            b.companyName,
-            b.socialCreditCode,
-            MAX(b.companyAddress) AS companyAddress,
-            MAX(b.companyPhone) AS companyPhone,
-            COUNT(1) AS invoiceCount,
-            SUM(CASE WHEN b.detailInvoiceAmount &gt; 0 THEN b.detailInvoiceAmount ELSE b.totalAmount END) AS invoiceAmount,
-            MAX(b.latestChargingTime) AS latestChargingTime
-        FROM (
-            SELECT
-                toi.id AS invoiceId,
-                TRIM(toi.name) AS companyName,
-                IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
-                MAX(toi.company_address) AS companyAddress,
-                MAX(toi.company_phone) AS companyPhone,
-                MAX(IFNULL(toi.total_amount, 0)) AS totalAmount,
-                SUM(IFNULL(tod.invoice_amount, 0)) AS detailInvoiceAmount,
-                MAX(co.start_time) AS latestChargingTime
-            FROM t_order_invoice toi
-            INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
-            LEFT JOIN t_charging_order co ON co.id = tod.order_id
-            LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
-            <where>
-                <include refid="enterpriseChargingBaseWhere" />
-            </where>
-            GROUP BY toi.id, TRIM(toi.name), TRIM(toi.tax_identification_number)
-        ) b
-        GROUP BY b.companyName, b.socialCreditCode
-        ORDER BY invoiceCount DESC
+            order_invoice_id AS invoiceId,
+            order_id AS orderId,
+            IFNULL(invoice_amount, 0) AS invoiceAmount
+        FROM t_order_invoice_detail
+        WHERE order_type = 1
+          AND order_invoice_id IN
+        <foreach collection="invoiceIds" item="invoiceId" open="(" separator="," close=")">
+            #{invoiceId}
+        </foreach>
     </select>
 
-    <select id="enterpriseTopSites" resultType="map">
+    <!-- 命中订单级条件的订单 id(co.id IN 走主键广播,条件同 enterpriseChargingOrderWhere,与明细口径一致) -->
+    <select id="enterpriseAnalysisMatchingOrderIds" resultType="long">
+        SELECT DISTINCT co.id
+        FROM t_charging_order co
+        <if test="data.siteType != null or data.partnerId != null or (data.partnerName != null and data.partnerName != '')">
+            INNER JOIN charging_pile_service.t_site s ON s.id = co.site_id
+        </if>
+        <if test="data.partnerName != null and data.partnerName != ''">
+            INNER JOIN charging_pile_service.t_partner p ON p.id = s.partner_id
+        </if>
+        <if test="data.phone != null and data.phone != ''">
+            INNER JOIN charging_pile_account.t_app_user au ON au.id = co.app_user_id
+        </if>
+        <where>
+            <include refid="enterpriseChargingOrderWhere" />
+        </where>
+    </select>
+
+    <!-- 命中订单数据(co.id IN 走主键广播,仅取 start_time/site_id) -->
+    <select id="enterpriseAnalysisChargingOrders" resultType="com.ruoyi.order.dto.EnterpriseChargingAggRow$Order">
         SELECT
-            s.name AS siteName,
-            COUNT(DISTINCT co.id) AS counts
-        FROM t_order_invoice toi
-        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
-        INNER JOIN t_charging_order co ON co.id = tod.order_id
-        LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
-        <where>
-            <include refid="enterpriseChargingBaseWhere" />
-            AND s.name IS NOT NULL
-        </where>
-        GROUP BY s.id, s.name
-        ORDER BY counts DESC
-        LIMIT 3
+            id AS orderId,
+            start_time AS startTime,
+            site_id AS siteId
+        FROM t_charging_order
+        WHERE id IN
+        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
+            #{orderId}
+        </foreach>
     </select>
 
-    <select id="enterpriseTopSitesByCompanies" resultType="map">
+    <!-- 站点名(charging_pile_service.t_site 单表,id IN) -->
+    <select id="enterpriseAnalysisSites" resultType="com.ruoyi.order.dto.EnterpriseChargingAggRow$Site">
         SELECT
-            TRIM(toi.name) AS companyName,
-            IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
-            s.name AS siteName,
-            COUNT(DISTINCT co.id) AS counts
-        FROM t_order_invoice toi
-        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
-        INNER JOIN t_charging_order co ON co.id = tod.order_id
-        LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
-        <where>
-            <include refid="enterpriseChargingBaseWhere" />
-            AND s.name IS NOT NULL
-            AND TRIM(toi.name) IN
-            <foreach collection="companyNames" item="companyName" open="(" separator="," close=")">
-                #{companyName}
-            </foreach>
-        </where>
-        GROUP BY TRIM(toi.name), TRIM(toi.tax_identification_number), s.id, s.name
-    </select>
-
-    <select id="enterpriseChargingTimes" resultType="java.time.LocalDateTime">
-        SELECT DISTINCT co.start_time
-        FROM t_order_invoice toi
-        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
-        INNER JOIN t_charging_order co ON co.id = tod.order_id
-        LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
-        <where>
-            <include refid="enterpriseChargingBaseWhere" />
-            AND co.start_time IS NOT NULL
-        </where>
-        ORDER BY co.start_time ASC
-    </select>
-
-    <select id="enterpriseChargingTimesByCompanies" resultType="map">
-        SELECT DISTINCT
-            TRIM(toi.name) AS companyName,
-            IFNULL(TRIM(toi.tax_identification_number), '') AS socialCreditCode,
-            co.start_time AS startTime
-        FROM t_order_invoice toi
-        INNER JOIN t_order_invoice_detail tod ON tod.order_invoice_id = toi.id
-        INNER JOIN t_charging_order co ON co.id = tod.order_id
-        LEFT JOIN charging_pile_service.t_site s ON s.id = co.site_id
-        <where>
-            <include refid="enterpriseChargingBaseWhere" />
-            AND co.start_time IS NOT NULL
-            AND TRIM(toi.name) IN
-            <foreach collection="companyNames" item="companyName" open="(" separator="," close=")">
-                #{companyName}
-            </foreach>
-        </where>
-        ORDER BY TRIM(toi.name), co.start_time
+            id AS siteId,
+            name AS siteName
+        FROM charging_pile_service.t_site
+        WHERE id IN
+        <foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
+            #{siteId}
+        </foreach>
     </select>
 
     <select id="enterpriseInvoiceIds" resultType="long">

--
Gitblit v1.7.1