The project finds that the query response is very slow, takes time to analyze and optimize, and is specially recorded.
(1) Background
The project adopts the MySQL database and Ibatis;
(2) query description
This query is used to query a certain number of users each time. Multi-Table Association is involved in the query. The specific query SQL statement is as follows:
- <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 ONS. ID=A. USER_ID
- LEFT JOIN
- (SELECT RESOURCE_ID, contact from company_resource_info
- WHERE UPDTIME>= # UPDResourceTime: TIMESTAMP #) R
- ONS. ID=R. CONTACT,
- Company_info C
- WHERES. COMPANY_ID= C. ID
- Group by s. ID
- LIMIT 15
- </Select>
Note that subqueries are used, involving temporary tables.
(3) analysis process
The analysis result of using the profiler provided by MySQL is as follows:
It can be observed that 99% of the time spent copying data to a temporary table is related to its subquery.
To be surprised, if only 15 pieces of data are LIMIT, the temporary data should not spend so much time. I personally think the problem should be caused by LIMIT's invalid subquery, that is to say, the subquery in it involves all the data, resulting in a large time consumption on the temporary table, which is not difficult to understand.
(4) Optimization
After thinking about the above reasons, the solution is clear, as long as the subqueries involved in it only query the data corresponding to the LIMIT.
The implementation method is as follows:
- <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
- WHERECONTACT= # 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 ONS. ID=A. USER_ID
- Left join company_info C ONS. COMPANY_ID= C. ID
- LIMIT 15
- </Select>
The main method is to first identify 15 pieces of LIMIT data that does not contain the subquery results and define a resultMap result set, call a query for each record to obtain the desired result.