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

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MySQL的左连接优化可以通过以下几种方式实现: 1. 索引优化:在左连接的两个表中,对于连接条件的字段建立索引,可以大大提高查询效率。 2. 子查询优化:将左连接中的子查询转换为临表,可以避免重复计算,提高查询效率。 3. 聚合函数优化:在左连接中使用聚合函数,应该尽量减少聚合函数的使用次数,可以通过子查询或者临表的方式实现。 4. 分页优化:在使用左连接进行分页查询,应该尽量减少查询的数据量,可以通过限制查询结果的数量或者使用缓存的方式实现。 5. 数据库结构优化:在设计数据库结构,应该尽量避免使用过多的左连接,可以通过拆分表或者使用其他关联方式实现。 ### 回答2: MySQL中的LEFT JOIN可以用于从左表中选择所有的行,并且根据指定的条件将与之匹配的右表中的行组合起来。在优化LEFT JOIN,可以采取以下几个步骤: 1. 确定JOIN条件:首先需要确保LEFT JOINJOIN条件是正确的,通常是通过关联左表和右表的字段来进行匹配。在确定JOIN条件,可以考虑创建合适的索引来加快查询速度。 2. 考虑使用合适的索引:在LEFT JOIN中,如果可以通过创建索引来加快查询速度,那么应该优先考虑这一方法。一般来说,可以在左表和右表的关联字段上创建索引,这样可以加快匹配过程。 3. 控制返回的列数:在LEFT JOIN中,返回的列数可能会比较多,如果不需要返回所有列,可以只选择需要的列,这样可以减少数据传输的开销,提高查询效率。 4. 注意数据量的大小:如果左表和右表中的数据量非常大,那么在执行LEFT JOIN可能会导致性能下降。可以考虑对数据进行分区或者进行适当的数据剪裁,以减少JOIN操作的数据量。 5. 使用子查询代替LEFT JOIN:有候可以使用子查询来代替LEFT JOIN操作,这样可能可以提高查询性能。但是需要注意,使用子查询也可能导致其他性能问题,需要仔细评估和测试。 总结起来,优化LEFT JOIN的关键是确定正确的JOIN条件、使用合适的索引、控制返回的列数和注意数据量的大小。通过合理的优化策略,可以提高LEFT JOIN的查询性能。 ### 回答3: MySQLLEFT JOIN可以通过优化来提高查询性能。下面是一些优化策略: 1. 确保合适的索引:为LEFT JOIN使用合适的索引是提高性能的关键。在连接条件和被连接表上创建索引可以加速查询。比如,如果连接条件是在被连接表上的字段上,可以为该字段创建索引。 2. 限制输出列:只选择需要的列,避免选择所有列。这样可以减少磁盘IO和网络传输的数据量,提高查询效率。 3. 使用条件过滤:在LEFT JOIN之前先使用WHERE子句进行条件过滤,可以减少需要连接的行数,优化查询性能。 4. 利用子查询:可以先创建一个子查询,将需要连接的数据集合缩小,再进行LEFT JOIN操作。这样可以减少需要连接的行数,提高查询效率。 5. 使用表别名:为表使用别名,可以简化查询语句,提高可读性。 6. 避免使用SELECT *:只选择需要的列,避免使用SELECT *语句,可以减少磁盘IO和网络传输的数据量,提高查询效率。 7. 可以考虑使用内连接:内连接可以通过使用INNER JOIN替代LEFT JOIN来避免不必要的行连接,提高查询性能。 8. 分析查询计划:使用EXPLAIN语句可以分析查询计划,了解查询语句的执行过程,找出可能的性能瓶颈,并对查询进行优化。 通过以上优化策略,可以提高MySQLLEFT JOIN查询性能,使查询更加高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

liuhaojavax

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

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

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

打赏作者

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

抵扣说明:

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

余额充值