mybatis的collection的性能问题

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

前言

本文记录一下,mybatis的collection使用不当,导致接口响应慢的问题。
过程是这样的,有一个分页接口,响应很慢。按道理一条sql的查询逻辑为啥会慢呢?

定位

所以我们开启了sql的日志打印,方便我们定位问题。将mapper的日志等级设置为debug模式即可。

logging:
  level:
    root: info
    mapper包名: debug
复制代码

可以发现,第一行就是我们的主sql,一个列表条件查询。但是查询完列表sql后,后面又执行了多次子查询的sql。 image.png 现在就需要我们看一下mapper的xml是怎么写的?

<select id="getProductInfoList" resultMap="productMap">
    select
    t.*
    from
    type_product t
    where 1=1 AND t.is_deleted = 'N'
    <if test="productTypeId != null and productTypeId != '' ">
        and t.product_type_id=#{productTypeId}
    </if>
    <if test="productTypeTagId != null and productTypeTagId != '' ">
        and t.product_type_tag_id=#{productTypeTagId}
    </if>
    group by product_id
</select>
复制代码

没啥问题,就是主条件查询的sql。那么后面这些子查询sql哪来的呢?我们再来看一下我们定义的resultMap

<resultMap id="productMap" type="com.baoyun.iyb.app.dao.dataobject.ProductInfo">
    <id column="id" property="id"></id>
    <result column="product_name" property="productName"></result>
    <result column="product_id" property="productId"></result>
    <result column="description" property="description"></result>
    <result column="product_img_url" property="productImgUrl"></result>
    <result column="gmt_modified" property="gmtModified"></result>
    <!-- 查询标签 -->
    <collection property="tags" column="product_id" ofType="com.baoyun.iyb.app.dao.dataobject.Tag"
                select="com.baoyun.iyb.app.dao.mapper.TagMapper.getTags">
        <result column="tag_name" property="tagName"></result>
        <result column="tag_title" property="tagTitle"></result>
        <result column="tag_content" property="tagContent"></result>
    </collection>
</resultMap>
复制代码

发现用到了collection来表示一对多的关系。其中定义了select,这个TagMapper.getTags就是日志打印出来的那些子查询。

方案

找到原因后,就应该想一下如何去避免它。其实collection还有另外一种用法,就是在主sql上join关联表去查询,通过使用collection来对数据进行聚合,成一个list。给一个案例

<resultMap type="Student" id="StudentMap2">
    <id column="id" property="id" />
    <result column="name" property="name" />
    <result column="job" property="job" />
    <collection property="scores" javaType="java.util.ArrayList" ofType="Score">
        <id column="id" property="id" />
        <result column="num" property="num" />
        <association property="subject" javaType="Subject">
            <id column="id" property="id" />
            <result column="name" property="name" />
        </association>
    </collection>
</resultMap>
<select id="queryStudents2" resultMap="StudentMap2" >
    SELECT stu.id,stu.name name,stu.job,sco.id id,sco.num num,sub.id id,sub.name name
    FROM t_student stu LEFT JOIN t_score sco ON stu.id = sco.sid LEFT JOIN t_subject sub ON sco.subject = sub.id
</select>
复制代码

这种方案可以看出只需要执行一次sql就行,缺点也很明显,就是代码的可重用性几乎没有了。

猜你喜欢

转载自juejin.im/post/7031349622933028878