动态 SQL 本身并不会直接“提升性能”,用得不好反而会降低性能。所谓“提升性能”,通常是指通过动态 SQL 实现更合理的 SQL 生成、减少无效计算、利用索引、降低锁竞争等。下面从原理 + 常见优化手段 + 注意事项系统说明。
❌ 动态 SQL ≠ 一定更快
✅ 动态 SQL = 更灵活,但性能取决于生成的 SQL 是否合理
例如:
OR 1=1、无用字段❌ 常见低效写法(MyBatis 示例):
SELECT * FROM orders
WHERE 1=1
<if test="status != null">
AND status = #{status}
</if>
<if test="createTime != null">
AND create_time >= #{createTime}
</if>
问题:
1=1 无意义✅ 优化写法:
SELECT * FROM orders
<where>
<if test="status != null">
AND status = #{status}
</if>
<if test="createTime != null">
AND create_time >= #{createTime}
</if>
</where>
✅ 好处:
✅ 场景:
status 索引create_time 索引❌ 一个 SQL 覆盖所有条件 → 索引失效
✅ 动态 SQL 拆成不同分支
<choose>
<when test="status != null">
SELECT * FROM orders WHERE status = #{status}
</when>
<when test="createTime != null">
SELECT * FROM orders WHERE create_time >= #{createTime}
</when>
<otherwise>
SELECT * FROM orders LIMIT 100
</otherwise>
</choose>
✅ 好处:
OR、function(status) 导致索引失效❌ 全字段更新:
UPDATE user
SET name=#{name},
age=#{age},
email=#{email}
WHERE id=#{id}
✅ 动态更新(只更新变化字段):
UPDATE user
<set>
<if test="name != null">name=#{name},</if>
<if test="age != null">age=#{age},</if>
<if test="email != null">email=#{email},</if>
</set>
WHERE id=#{id}
✅ 好处:
❌ 深分页:
SELECT * FROM orders
LIMIT 1000000, 20
✅ 动态 SQL + 游标分页:
SELECT * FROM orders
WHERE id > #{lastId}
ORDER BY id
LIMIT 20
✅ 好处:
OFFSET 扫描大量数据✅ 按时间 / 租户动态选择表:
SELECT * FROM order_${year}_${month}
WHERE user_id = #{userId}
✅ 好处:
数据库对 完全相同 SQL 会缓存执行计划
动态 SQL 变化太多 → 执行计划缓存失效
✅ 对策:
❌ 危险写法:
"SELECT * FROM user WHERE name = '" + name + "'"
✅ 正确写法(参数化):
SELECT * FROM user WHERE name = #{name}
✅ 好处:
AND id IN
<foreach collection="ids" open="(" close=")" item="id">
#{id}
</foreach>
✅ 优化:
IN 数量(如 ≤ 1000)✅ 不是动态 SQL 更快,而是:
| 优化点 | 说明 |
|---|---|
| 减少无效条件 | 让优化器选对索引 |
| 分支生成最优 SQL | 不同条件走不同索引 |
| 减少更新范围 | 降低锁和日志 |
| 避免大分页 | 用游标 / 主键 |
| 参数化查询 | 利用预编译 |
如果你愿意,可以告诉我:
我可以直接帮你改写并给出性能对比方案。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。