相关SQL语句说明

本案例中,使用如下的查询语句,在优化前,涉及到多表关联和子查询以及分页,使用了select * ,性能差,不可控:

SELECT *
FROM (
    SELECT *
    FROM order_main om
    LEFT JOIN order_detail od ON om.order_id = od.order_id
    WHERE om.order_status IN (1, 2, 3)
      AND om.create_time >= '2025-01-01 00:00:00'
      AND om.user_id IN (
          SELECT user_id
          FROM user_info
          WHERE user_level >= 2
            AND is_active = 1
      )
) AS order_full
LEFT JOIN product_info pi ON order_full.product_id = pi.product_id
WHERE pi.is_on_sale = 1
ORDER BY order_full.create_time DESC, order_full.order_id DESC
LIMIT 0, 20;

代码优化说明

样例代码如下:

代码块
SELECT 
    order_full.order_id,
    order_full.user_id,
    order_full.product_id,
    order_full.order_status,
    order_full.create_time,
    -- ... 其他需要的字段
    pi.product_name,
    pi.is_on_sale
FROM (
    SELECT 
        om.order_id,
        om.user_id,
        od.product_id, -- 假设 product_id 来自 order_detail
        om.order_status,
        om.create_time,
        -- ... 其他需要的字段
        ROW_NUMBER() OVER (ORDER BY om.create_time DESC, om.order_id DESC) AS rn
    FROM order_main om
    -- 假设 order_main 表有按日期分区的字段 dt,根据 create_time 补充过滤
    LEFT JOIN order_detail od ON om.order_id = od.order_id
    INNER JOIN user_info ui ON om.user_id = ui.user_id 
        AND ui.user_level >= 2 
        AND ui.is_active = 1
    WHERE om.order_status IN (1, 2, 3)
      AND om.create_time >= '2025-01-01 00:00:00'
      -- 根据实际分区键调整,例如假设分区字段为 dt,且与 create_time 同日期
      AND om.dt >= '2025-01-01'
) AS order_full
LEFT JOIN product_info pi ON order_full.product_id = pi.product_id 
    AND pi.is_on_sale = 1 -- 过滤条件下推
WHERE order_full.rn <= 20 -- 提前限制数据量
ORDER BY order_full.create_time DESC, order_full.order_id DESC;

优化点说明:

  1. 使用显式字段列表代替 SELECT *,减少I/O和Shuffle数据量(请根据实际需求替换字段名)。

  2. 将 IN 子查询改为 JOIN,可能利用MapJoin或更优的执行计划。

  3. 补充了假设的分区过滤条件 om.dt >= '2025-01-01',请根据实际分区键调整。

  4. 将 product_info 的过滤条件下推到 JOIN 条件中。

  5. 使用子查询提前进行排序和分页,减少参与最终全局排序的数据量。

代码优化效果截图

案例说明 - 图1