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

数据库性能优化指南

问题分析

根据对Mapper XML文件的检查,发现以下可能导致数据返回慢的主要问题:

1. 使用 SELECT * 查询所有字段

  • 问题SELECT * 查询会返回表中的所有列,增加网络传输量和处理时间
  • 影响文件:ManagersMapper.xml中的多个查询

2. 复杂的JOIN和嵌套WHERE条件

  • 问题:复杂的JOIN操作和多层嵌套条件会增加数据库解析和执行时间
  • 影响文件:UsersMapper.xml中的getAuthorizedCustomersgetAuthorizedUserIds查询

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);

验证优化效果

优化后,建议通过以下方式验证性能改进:

  1. 使用EXPLAIN分析SQL执行计划

    EXPLAIN SELECT manager_id, id, managerId, managercompany, managerdepartment,
           organization, role, root, userName, assistant
    FROM managers WHERE userName = 'someName';
    
  2. 添加性能监控日志 在Service层添加方法执行时间记录。

  3. 压力测试 使用JMeter等工具进行压力测试,比较优化前后的响应时间。

额外建议

  1. 考虑读写分离 对于高并发场景,考虑实现数据库读写分离。

  2. 使用数据库连接池 确保使用高效的连接池管理数据库连接。

  3. 定期清理和优化数据库 定期执行VACUUM(PostgreSQL)或OPTIMIZE TABLE(MySQL)等操作。

  4. 考虑使用NoSQL缓存热点数据 对于频繁访问的数据,可以考虑使用Redis等NoSQL数据库进行缓存。


此优化指南由自动化工具生成,建议根据实际情况进行调整和测试。