MySQL关联查询优化实例

原文地址:http://www.linuxidc.com/Linux/2011-11/46585.htm



项目中发现有一个查询响应非常慢,花时间分析以及优化,特地记录。
(1)背景

项目采用MySQL数据库,操作使用Ibatis;

(2)查询说明

这个查询是每次查询一定数目的用户信息,查询中涉及到多表关联,具体查询SQL如下

<select id="select"  parameterClass="UserCompany" resultClass="UserCompany">  
                SELECT S.NAME as name, 
                    S.IMAGE as image, 
                    S.ID as id, 
                    C.NAME as companyName, 
                    C.ID as companyId, 
                    A.FILE_NAME AS resourceFileName, 
                    A.FILE_PATH AS resourceFilePath, 
                    A.FILE_ID AS resourceFileId, 
                    COUNT(R.CONTACT) AS updResourceSize   
                    from sys_user_info S  
                    LEFT JOIN ATTACH_FILE_INFO A ON S.ID = A.USER_ID 
            LEFT JOIN  
                (SELECT RESOURCE_ID,CONTACT FROM company_resource_info  
                WHERE UPDTIME >= #UPDResourceTime:TIMESTAMP# ) R  
            ON  S.ID = R.CONTACT, 
                    company_info C  
                    WHERE S.COMPANY_ID = C.ID 
                    GROUP BY S.ID 
            LIMIT 15 
    </select> 
注意其中用到了子查询,涉及到临时表
(3)分析过程

使用MySQL自带的profiler分析结果如下图



观察可得,99%的时间花在了拷贝数据到临时表上,也就是与其中的子查询有关系。

想来奇怪,如果只是LIMIT 15条数据,临时数据不应该花费这么多时间;个人觉得问题应该出在LIMIT对于里面的子查询无效,也就是里面的子查询会涉及到全部数据,从而导致临时表消耗很大的时间,这样就不难理解了。

(4)优化

想清楚了上面的原因,解决的思路也就比较清楚了,只要让里面涉及的子查询只查LIMIT对应的数据就可以了。

重新实行的方式如下:

<resultMap class="cn.com.steel.wuyou.model.UserCompany" id="UserCompanyMap"> 
        <result property="name" column="name" /> 
        <result property="image" column="image" /> 
        <result property="id" column="id" /> 
        <result property="companyName" column="companyName" /> 
        <result property="companyId" column="companyId" /> 
        <result property="resourceFileName" column="resourceFileName" /> 
        <result property="resourceFilePath" column="resourceFilePath" /> 
        <result property="resourceFileId" column="resourceFileId" /> 
        <result property="UPDResourceTime" column="UPDResourceTime" /> 
        <result property="updResourceSize" column="{CONTACT=id,udpResourceTime=UPDResourceTime}" 
            select="steel_userCompany.selectUpdResourceSize" /> 
    </resultMap> 
 
    <select id="selectUpdResourceSize" parameterClass="java.util.HashMap" 
        resultClass="int"> 
        SELECT COUNT(1) FROM company_resource_info 
        WHERE CONTACT = #CONTACT# 
        and UPDTIME >= #UPDResourceTime:TIMESTAMP# 
    </select> 
 
 
    <select id="select" parameterClass="UserCompany" resultMap="UserCompanyMap"> 
        SELECT S.NAME as name, 
        S.IMAGE as image, 
        S.ID as id, 
        C.NAME as companyName, 
        C.ID as companyId, 
        A.FILE_NAME AS resourceFileName, 
        A.FILE_PATH AS resourceFilePath, 
        A.FILE_ID AS resourceFileId, 
        #UPDResourceTime:TIMESTAMP# as UPDResourceTime 
        from sys_user_info S 
        LEFT JOIN ATTACH_FILE_INFO A ON S.ID = A.USER_ID 
        LEFT JOIN company_info C ON S.COMPANY_ID = C.ID 
        LIMIT 15 
    </select> 
主要的做法就是,每次先查出LIMIT 15条不含子查询结果的数据,定义一个resultMap映射结果集,针对每一条记录再去分别调用一次查询从而得到最后想要的结果。 linux

猜你喜欢

转载自wangxiaoxu.iteye.com/blog/2254985