You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用MySQL Inner Join替代多SELECT语句改写查询

MySQL查询改写:用JOIN替代子查询优化性能

我用SELECT语句写了一个从两张表取数据的查询,能正常运行但执行和取数耗时很长(每张表仅40k行数据)。我是MySQL逻辑与查询的新手,希望用Inner Join改写这个查询。

原查询语句:

SELECT * FROM 
    (SELECT a_sno AS UID,a_name AS `Name`,a_emailid AS EmailID, 
            a_mobile AS Mobile,a_othermobile AS Broker_Mobile,
            a_vendorname AS Broker_Name,a_planname AS Subscription_Plan, 
            a_createdtime AS Date_of_Registration, 
            a_plandatetill AS Subscription_End_Date,
            CAST(
                IFNULL(
                    (SELECT a_amount 
                    FROM details_payments 
                    WHERE a_status='success' 
                    AND a_uid=ll.a_sno 
                    ORDER BY a_sno DESC LIMIT 1)
                ,'-') 
             AS CHAR) AS Subscription_Amount,
             CAST(
                IFNULL(
                    (SELECT a_confirm_time 
                    FROM details_payments 
                    WHERE a_status='success' 
                    AND a_uid=ll.a_sno ORDER BY a_sno DESC LIMIT 1)
                ,'-')
             AS CHAR) AS Date_of_Subscription,
             CAST(
                IFNULL(
                    (SELECT a_registerednotsub_rmks 
                    FROM whatsapp.details_remarks 
                    WHERE a_uid=ll.a_sno 
                    ORDER BY a_sno DESC LIMIT 1)
                ,'-')
             AS CHAR) AS Remarks
-- ,IFNULL((SELECT COUNT(*) FROM details_payments WHERE a_status='success' AND a_uid=ll.a_sno),'') AS total_count_payments
     FROM details_login ll 
     WHERE ll.a_createdtime BETWEEN "2022-05-09" AND "2022-06-14" 
     AND ll.a_activated = 1 
     AND (ll.a_planname = 'Free Trial' OR ll.a_planname = '-' OR ll.a_planname = '')
     AND(a_fyersid != '-' 
         OR (a_fyersid = '-' 
             AND ll.a_mobile !='0' 
             AND ll.a_mobile != '' 
             AND ll.a_mobile !='-' 
             AND LENGTH(ll.a_mobile) = '10' 
             AND ll.a_mobile != '6666666666' 
             AND ll.a_mobile != '7777777777'
             AND ll.a_mobile != '8888888888' 
             AND ll.a_mobile != '9999999999' 
             AND (a_mobile LIKE '6%' AND LENGTH(a_mobile) = '10')
             OR (a_mobile LIKE '7%' AND LENGTH(a_mobile) = '10') 
             OR (a_mobile LIKE '8%' AND LENGTH(a_mobile) = '10') 
             OR (a_mobile LIKE '9%' AND LENGTH(a_mobile) = '10')
         )
      )
      ORDER BY a_sno DESC) jjjjj 
      WHERE Subscription_Amount ='-' 
      GROUP BY Mobile;

改写后的查询(LEFT JOIN + 窗口函数)

原查询的性能瓶颈在于多个逐行执行的关联子查询,改用窗口函数先批量获取每个用户的最新记录,再通过JOIN关联主表,能大幅提升效率:

SELECT 
    ll.a_sno AS UID,
    ll.a_name AS `Name`,
    ll.a_emailid AS EmailID,
    ll.a_mobile AS Mobile,
    ll.a_othermobile AS Broker_Mobile,
    ll.a_vendorname AS Broker_Name,
    ll.a_planname AS Subscription_Plan,
    ll.a_createdtime AS Date_of_Registration,
    ll.a_plandatetill AS Subscription_End_Date,
    CAST(IFNULL(p.a_amount, '-') AS CHAR) AS Subscription_Amount,
    CAST(IFNULL(p.a_confirm_time, '-') AS CHAR) AS Date_of_Subscription,
    CAST(IFNULL(r.a_registerednotsub_rmks, '-') AS CHAR) AS Remarks
FROM details_login ll
-- 关联用户最新的成功支付记录
LEFT JOIN (
    SELECT 
        a_uid,
        a_amount,
        a_confirm_time,
        ROW_NUMBER() OVER(PARTITION BY a_uid ORDER BY a_sno DESC) AS rn
    FROM details_payments
    WHERE a_status = 'success'
) p ON ll.a_sno = p.a_uid AND p.rn = 1
-- 关联用户最新的备注记录
LEFT JOIN (
    SELECT 
        a_uid,
        a_registerednotsub_rmks,
        ROW_NUMBER() OVER(PARTITION BY a_uid ORDER BY a_sno DESC) AS rn
    FROM whatsapp.details_remarks
) r ON ll.a_sno = r.a_uid AND r.rn = 1
WHERE 
    ll.a_createdtime BETWEEN '2022-05-09' AND '2022-06-14'
    AND ll.a_activated = 1
    AND ll.a_planname IN ('Free Trial', '-', '')
    AND (
        ll.a_fyersid != '-'
        OR (
            ll.a_fyersid = '-'
            AND ll.a_mobile NOT IN ('0', '', '-', '6666666666', '7777777777', '8888888888', '9999999999')
            AND LENGTH(ll.a_mobile) = 10
            AND ll.a_mobile REGEXP '^[6-9]'
        )
    )
    AND p.a_amount IS NULL -- 等价于原查询的Subscription_Amount = '-'
GROUP BY ll.a_mobile;

优化说明

  • 窗口函数ROW_NUMBER()对支付表和备注表按用户分组,仅扫描两张表各一次,替代原查询中逐行执行的N次子查询
  • 简化手机号校验逻辑:用REGEXP '^[6-9]'替代多个LIKE条件,用IN/NOT IN替代重复的OR/!=,可读性和执行效率都更高
  • 原查询中Subscription_Amount='-'等价于无成功支付记录,直接用p.a_amount IS NULL判断更直接

内容的提问来源于stack exchange,提问作者Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:31:02