mysql分页列表使用LEFT JOIN时的优化方法

本文介绍了一种在MySQL中进行分页查询时的优化方法,特别是当查询涉及多个表的LEFT JOIN操作时。通过调整JOIN顺序和减少不必要的JOIN,可以显著提高查询效率,将页面刷新时间从1100ms降低到50ms。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mysql分页列表使用LEFT JOIN时的优化方法

分页列表查询一般格式

  • 取分页数据
SELECT *
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id
LEFT JOIN table3 t3 ON t3.id = t1.id
LEFT JOIN table4 t4 ON t4.id = t1.id
WHERE t1.id = 1 AND t2. ...
LIMIT 0,30
  • 取总数
SELECT COUNT(0)
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id
LEFT JOIN table3 t3 ON t3.id = t1.id
LEFT JOIN table4 t4 ON t4.id = t1.id
WHERE t1.id = 1 AND t2. ...
缺点
  • LEFT JOIN消耗性能
  • 全部LEFT JOIN后再取分页
  • 取总数时候不必要的LEFT JOIN影响性能
优化
  • WHERE 条件语句用不到的LEFT JOIN的表,放到取分页后面
  • 取总数时候不必要的LEFT JOIN不要
  • 取分页数据
SELECT *
FROM (
    SELECT *
    FROM table1 t1
    LEFT JOIN table2 t2 ON t2.id = t1.id
    LEFT JOIN table3 t3 ON t3.id = t1.id
    WHERE t1.id = 1 AND t2. ...
    LIMIT 0,30
    )t
LEFT JOIN table4 t4 ON t4.id = t1.id
    
  • 取总数
SELECT COUNT(0)
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id
LEFT JOIN table2 t3 ON t3.id = t1.id
WHERE t1.id = 1 AND t2. ...

具体实际应用

网站分页列表
优化前
  • 数据量:9741
  • 每页显示30条数据
  • 平均每页刷新耗时:1100ms
  • 列表数据
SELECT 
    w.*,
    d.`name` AS deptName,
    IFNULL(de.`name`,'') AS superviseName,
    CASE WHEN w.school_id IS NULL THEN d.`name` ELSE s.name END AS schoolName
    FROM website w
    LEFT JOIN sys_dept d ON d.id = w.dept_id
    LEFT JOIN sys_dept de ON de.id = w.supervise_id
    LEFT JOIN sys_dept scan ON scan.id = w.scan_id
    LEFT JOIN sys_dept verify ON verify.id = w.verify_id
    LEFT JOIN sys_dept_info i ON i.dept_id = w.dept_id
    LEFT JOIN dictionary_item item ON i.area_id = item.id
    LEFT JOIN school s ON s.id = w.school_id
    WHERE w.is_del = 0
    <if test="deptId != null and deptId != ''">
        AND d.id = #{deptId}
    </if>
    <if test="name != null and name != ''">
        AND (UPPER(w.name) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%')))
        OR UPPER(w.py) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%'))))
    </if>
    <if test="url != null and url != ''">
        AND UPPER(w.url) LIKE UPPER(CONCAT('%',CONCAT(#{url},'%')))
    </if>
    <if test="linkman != null and linkman != ''">
        AND UPPER(w.contact_name) LIKE UPPER(CONCAT('%',CONCAT(#{linkman},'%')))
    </if>
    ORDER BY w.create_date DESC
    <if test="pageSize != null ">
        LIMIT #{offset}, #{pageSize}
    </if>
  • 网站数量
SELECT 
    COUNT(0)
    FROM website w
    LEFT JOIN sys_dept d ON d.id = w.dept_id
    LEFT JOIN sys_dept de ON de.id = w.supervise_id
    LEFT JOIN sys_dept scan ON scan.id = w.scan_id
    LEFT JOIN sys_dept verify ON verify.id = w.verify_id
    LEFT JOIN sys_dept_info i ON i.dept_id = w.dept_id
    LEFT JOIN dictionary_item item ON i.area_id = item.id
    LEFT JOIN school s ON s.id = w.school_id
    WHERE w.is_del = 0
    <if test="deptId != null and deptId != ''">
        AND d.id = #{deptId}
    </if>
    <if test="name != null and name != ''">
        AND (UPPER(w.name) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%')))
        OR UPPER(w.py) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%'))))
    </if>
    <if test="url != null and url != ''">
        AND UPPER(w.url) LIKE UPPER(CONCAT('%',CONCAT(#{url},'%')))
    </if>
    <if test="linkman != null and linkman != ''">
        AND UPPER(w.contact_name) LIKE UPPER(CONCAT('%',CONCAT(#{linkman},'%')))
    </if>
优化
  • 数据量:9741
  • 每页显示300条数据
  • 平均每页刷新耗时:120ms
  • 每页显示30条数据
  • 平均每页刷新耗时:50ms
  • 列表数据
SELECT
    t.*,
    item.name                 AS areaName,
    IFNULL(scan.`name`, '')   AS scanName,
    IFNULL(verify.`name`, '') AS verifyName,
    de.`name`                 AS superviseName
    FROM (
        SELECT
            w.id,
            w.name,
            w.url,
            w.dept_id,
            w.scan_id,
            w.supervise_id,
            w.verify_id,
            CASE WHEN w.school_id IS NULL THEN d.`name` ELSE s.name END  AS schoolName,
            d.`name`                                                     AS deptName
        FROM website w
        LEFT JOIN sys_dept d ON d.id = w.dept_id
        LEFT JOIN school s ON s.id = w.school_id
        WHERE w.is_del = 0
        <if test="deptId != null and deptId != ''">
            AND d.id = #{deptId}
        </if>
        <if test="deptName != null and deptName != ''">
            AND (UPPER(d.name) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%')))
            OR UPPER(d.py) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%')))
            OR UPPER(s.name) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%'))))
        </if>
        <if test="name != null and name != ''">
            AND (UPPER(w.name) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%')))
            OR UPPER(w.py) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%'))))
        </if>
        <if test="url != null and url != ''">
            AND UPPER(w.url) LIKE UPPER(CONCAT('%',CONCAT(#{url},'%')))
        </if>
        <if test="linkman != null and linkman != ''">
            AND UPPER(w.contact_name) LIKE UPPER(CONCAT('%',CONCAT(#{linkman},'%')))
        </if>
        ORDER BY w.create_date DESC
        <if test="pageSize != null ">
            LIMIT #{offset}, #{pageSize}
        </if>
    ) t
    LEFT JOIN sys_dept_info i ON i.dept_id = t.dept_id
    LEFT JOIN dictionary_item item ON i.area_id = item.id
    LEFT JOIN sys_dept de ON de.id = t.supervise_id
    LEFT JOIN sys_dept scan ON scan.id = t.scan_id
    LEFT JOIN sys_dept verify ON verify.id = t.verify_id
  • 网站数量
SELECT
    COUNT(0)
    FROM (
        SELECT
            w.id,
            w.name,
            w.url,
            w.dept_id,
            w.scan_id,
            w.supervise_id,
            w.verify_id,
            CASE WHEN w.school_id IS NULL THEN d.`name` ELSE s.name END  AS schoolName,
            d.`name`                                                     AS deptName
        FROM website w
        LEFT JOIN sys_dept d ON d.id = w.dept_id
        LEFT JOIN school s ON s.id = w.school_id
        WHERE w.is_del = 0
        <if test="deptId != null and deptId != ''">
            AND d.id = #{deptId}
        </if>
        <if test="deptName != null and deptName != ''">
            AND (UPPER(d.name) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%')))
            OR UPPER(d.py) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%')))
            OR UPPER(s.name) LIKE UPPER(CONCAT('%',CONCAT(#{deptName},'%'))))
        </if>
        <if test="name != null and name != ''">
            AND (UPPER(w.name) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%')))
            OR UPPER(w.py) LIKE UPPER(CONCAT('%',CONCAT(#{name},'%'))))
        </if>
        <if test="url != null and url != ''">
            AND UPPER(w.url) LIKE UPPER(CONCAT('%',CONCAT(#{url},'%')))
        </if>
        <if test="linkman != null and linkman != ''">
            AND UPPER(w.contact_name) LIKE UPPER(CONCAT('%',CONCAT(#{linkman},'%')))
        </if>
        ORDER BY w.create_date DESC
        <if test="pageSize != null ">
            LIMIT #{offset}, #{pageSize}
        </if>
    ) t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuhaojavax

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值