You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.0 KiB
9.0 KiB
数据库性能优化指南
问题分析
根据对Mapper XML文件的检查,发现以下可能导致数据返回慢的主要问题:
1. 使用 SELECT * 查询所有字段
- 问题:
SELECT *查询会返回表中的所有列,增加网络传输量和处理时间 - 影响文件:ManagersMapper.xml中的多个查询
2. 复杂的JOIN和嵌套WHERE条件
- 问题:复杂的JOIN操作和多层嵌套条件会增加数据库解析和执行时间
- 影响文件:UsersMapper.xml中的
getAuthorizedCustomers和getAuthorizedUserIds查询
3. 可能缺少必要的索引
- 问题:频繁用于查询条件的字段可能缺少索引,导致全表扫描
- 影响字段:userId, phoneNumber, type, level, managerId等
4. 未使用分页查询
- 问题:查询大量数据时未使用分页,一次性返回过多数据
- 影响文件:selectAllManagers等查询
优化方案
1. 优化SQL查询语句
1.1 替换 SELECT * 为具体字段
修改前 (ManagersMapper.xml):
<select id="selectAllManagers" resultMap="managersMap">
SELECT * FROM managers ORDER BY userName
</select>
修改后:
<select id="selectAllManagers" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers ORDER BY userName
</select>
对其他使用 SELECT * 的查询也进行类似修改。
1.2 优化复杂的JOIN查询
修改建议 (UsersMapper.xml):
- 将复杂的嵌套条件拆分为更简单的部分
- 使用子查询代替部分复杂JOIN
- 考虑使用临时表缓存中间结果
1.3 添加分页查询
修改前:
<select id="selectAllManagers" resultMap="managersMap">
SELECT * FROM managers ORDER BY userName
</select>
修改后:
<select id="selectAllManagersWithPagination" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers
ORDER BY userName
LIMIT #{limit} OFFSET #{offset}
</select>
同时在Mapper接口中添加对应的方法。
2. 添加必要的数据库索引
建议在以下字段上添加索引:
-- 在users表上添加索引
CREATE INDEX idx_users_userId ON users(userId);
CREATE INDEX idx_users_phoneNumber ON users(phoneNumber);
CREATE INDEX idx_users_type ON users(type);
CREATE INDEX idx_users_level ON users(level);
CREATE INDEX idx_users_created_at ON users(created_at);
-- 在managers表上添加索引
CREATE INDEX idx_managers_id ON managers(id);
CREATE INDEX idx_managers_userName ON managers(userName);
CREATE INDEX idx_managers_managerId ON managers(managerId);
-- 在usermanagements表上添加索引
CREATE INDEX idx_usermanagements_userId ON usermanagements(userId);
CREATE INDEX idx_usermanagements_managerId ON usermanagements(managerId);
CREATE INDEX idx_usermanagements_userName ON usermanagements(userName);
CREATE INDEX idx_usermanagements_organization ON usermanagements(organization);
CREATE INDEX idx_usermanagements_managerdepartment ON usermanagements(managerdepartment);
3. 添加缓存机制
3.1 在MyBatis中添加二级缓存
在Mapper XML文件中添加缓存配置:
<mapper namespace="com.example.web.mapper.ManagersMapper">
<!-- 添加二级缓存 -->
<cache
eviction="LRU"
flushInterval="60000"
size="512"
readOnly="true"/>
<!-- 现有映射内容 -->
<!-- ... -->
</mapper>
3.2 在Service层添加本地缓存
在Service类中使用Guava Cache或Caffeine等本地缓存库。
4. 优化结果集映射
4.1 优化ResultMap定义
确保ResultMap只映射必要的字段,避免不必要的映射。
4.2 使用Constructor Args映射
对于频繁使用的DTO,可以考虑使用构造函数参数映射,提高性能。
具体优化实施
优化ManagersMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.web.mapper.ManagersMapper">
<!-- 添加二级缓存 -->
<cache
eviction="LRU"
flushInterval="60000"
size="512"
readOnly="true"/>
<resultMap id="managersMap" type="com.example.web.entity.Managers">
<id column="manager_id" property="manager_id"/>
<result column="id" property="id"/>
<result column="managerId" property="managerId"/>
<result column="managercompany" property="managercompany"/>
<result column="managerdepartment" property="managerdepartment"/>
<result column="organization" property="organization"/>
<result column="role" property="role"/>
<result column="root" property="root"/>
<result column="created_at" property="created_at"/>
<result column="updated_at" property="updated_at"/>
<result column="userName" property="userName"/>
<result column="assistant" property="assistant"/>
</resultMap>
<!-- 在 ManagersMapper.xml 中添加 -->
<select id="selectByUserNameAndManagerId" parameterType="map" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers
WHERE userName = #{userName} AND managerId = #{managerId}
</select>
<!-- 根据企业ID查询负责人信息 -->
<select id="selectManagersByEnterpriseId" parameterType="String" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers WHERE id = #{id}
</select>
<!-- 查询所有负责人信息 -->
<select id="selectAllManagers" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers ORDER BY userName
</select>
<!-- 分页查询负责人信息 -->
<select id="selectAllManagersWithPagination" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers
ORDER BY userName
LIMIT #{limit} OFFSET #{offset}
</select>
<!-- 根据负责人姓名查询 -->
<select id="selectByUserName" parameterType="String" resultMap="managersMap">
SELECT manager_id, id, managerId, managercompany, managerdepartment,
organization, role, root, userName, assistant
FROM managers WHERE userName = #{userName}
</select>
<!-- 插入负责人信息 -->
<insert id="insertManagers" parameterType="com.example.web.entity.Managers">
INSERT INTO managers (
id, managerId, managercompany, managerdepartment,
organization, role, root, created_at, updated_at,
userName, assistant
) VALUES (
#{id}, #{managerId}, #{managercompany}, #{managerdepartment},
#{organization}, #{role}, #{root}, #{created_at}, #{updated_at},
#{userName}, #{assistant}
)
</insert>
<!-- 更新负责人信息 -->
<update id="updateManagers" parameterType="com.example.web.entity.Managers">
UPDATE managers
SET
managercompany = #{managercompany},
managerdepartment = #{managerdepartment},
organization = #{organization},
role = #{role},
userName = #{userName},
assistant = #{assistant},
updated_at = #{updated_at}
WHERE id = #{id}
</update>
</mapper>
优化UsersMapper接口添加分页方法
在UsersMapper.java中添加分页查询方法:
// 分页查询授权客户
List<UserProductCartDTO> getAuthorizedCustomersWithPagination(Map<String, Object> params);
// 获取授权客户总数
int getAuthorizedCustomersCount(Map<String, Object> params);
验证优化效果
优化后,建议通过以下方式验证性能改进:
-
使用EXPLAIN分析SQL执行计划
EXPLAIN SELECT manager_id, id, managerId, managercompany, managerdepartment, organization, role, root, userName, assistant FROM managers WHERE userName = 'someName'; -
添加性能监控日志 在Service层添加方法执行时间记录。
-
压力测试 使用JMeter等工具进行压力测试,比较优化前后的响应时间。
额外建议
-
考虑读写分离 对于高并发场景,考虑实现数据库读写分离。
-
使用数据库连接池 确保使用高效的连接池管理数据库连接。
-
定期清理和优化数据库 定期执行VACUUM(PostgreSQL)或OPTIMIZE TABLE(MySQL)等操作。
-
考虑使用NoSQL缓存热点数据 对于频繁访问的数据,可以考虑使用Redis等NoSQL数据库进行缓存。
此优化指南由自动化工具生成,建议根据实际情况进行调整和测试。