使用 concat 和 filesort 时 mysql 查询慢

Posted

技术标签:

【中文标题】使用 concat 和 filesort 时 mysql 查询慢【英文标题】:slow mysql query when using concat and filesort 【发布时间】:2018-02-13 15:30:04 【问题描述】:

这个系统上的所有查询都很快,除非我将“最近状态”和/或“最近状态(扩展)”添加到我的搜索中。

Candidates Page with Re4cent Status selected

来自慢日志的查询。

SELECT SQL_CALC_FOUND_ROWS
candidate.candidate_id AS candidateID,
candidate.candidate_id AS exportID,
candidate.is_hot AS isHot,
candidate.date_modified AS dateModifiedSort,
candidate.date_created AS dateCreatedSort,
IF(candidate_joborder_submitted.candidate_joborder_id, 1, 0) AS submitted,
IF(attachment_id, 1, 0) AS attachmentPresent,
candidate.first_name AS firstName,
candidate.last_name AS lastName,
candidate.city AS city,
candidate.state AS state,
candidate.key_skills AS keySkills,
owner_user.first_name AS ownerFirstName,owner_user.last_name AS ownerLastName,CONCAT(owner_user.last_name, owner_user.first_name) AS ownerSort,
DATE_FORMAT(candidate.date_created, '%m-%d-%y') AS dateCreated,
DATE_FORMAT(candidate.date_modified, '%m-%d-%y') AS dateModified,
(
SELECT
CONCAT(
'<a href="index.php?m=joborders&amp;a=show&amp;jobOrderID=',
joborder.joborder_id,
'" title="',
joborder.title,
' (',
company.name,
')">',
candidate_joborder_status.short_description,
'</a>'
)
FROM
candidate_joborder
LEFT JOIN candidate_joborder_status
ON candidate_joborder_status.candidate_joborder_status_id = candidate_joborder.status
LEFT JOIN joborder
ON joborder.joborder_id = candidate_joborder.joborder_id
LEFT JOIN company
ON joborder.company_id = company.company_id
WHERE
candidate_joborder.candidate_id = candidate.candidate_id
ORDER BY
candidate_joborder.date_modified DESC
LIMIT 1
) AS lastStatus
FROM
candidate
LEFT JOIN attachment
ON candidate.candidate_id = attachment.data_item_id
AND attachment.data_item_type = 100
LEFT JOIN candidate_joborder AS candidate_joborder_submitted
ON candidate_joborder_submitted.candidate_id = candidate.candidate_id
AND candidate_joborder_submitted.status >= 400
AND candidate_joborder_submitted.site_id = 1
AND candidate_joborder_submitted.status != 650
LEFT JOIN user AS owner_user ON candidate.owner = owner_user.user_id LEFT JOIN saved_list_entry
ON saved_list_entry.data_item_type = 100
AND saved_list_entry.data_item_id = candidate.candidate_id
AND saved_list_entry.site_id = 1
WHERE
candidate.site_id = 1

GROUP BY candidate.candidate_id

ORDER BY dateModifiedSort DESC
LIMIT 0, 15;

解释结果

'1', 'PRIMARY', 'attachment', 'system', 'IDX_type_id,IDX_data_item_id,dataitem1', NULL, NULL, NULL, '0', 'const row not found'
'1', 'PRIMARY', 'candidate', 'ALL', 'IDX_site_first_last_modified,IDX_site_id_email_1_2', NULL, NULL, NULL, '8645', 'Using where; Using temporary; Using filesort'
'1', 'PRIMARY', 'candidate_joborder_submitted', 'ref', 'IDX_candidate_id,IDX_site_id,IDX_status_special,IDX_site_joborder', 'IDX_candidate_id', '4', 'opencats.candidate.candidate_id', '1', 'Using where'
'1', 'PRIMARY', 'owner_user', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'opencats.candidate.owner', '1', 'Using where'
'1', 'PRIMARY', 'saved_list_entry', 'ref', 'IDX_data_item_type,IDX_data_item_id,IDX_type_id', 'IDX_data_item_id', '4', 'opencats.candidate.candidate_id', '1', 'Using where'
'2', 'DEPENDENT SUBQUERY', 'candidate_joborder', 'index', 'IDX_candidate_id', 'IDX_date_modified', '8', NULL, '1', 'Using where'
'2', 'DEPENDENT SUBQUERY', 'candidate_joborder_status', 'eq_ref', 'PRIMARY,status1', 'PRIMARY', '4', 'opencats.candidate_joborder.status', '1', ''
'2', 'DEPENDENT SUBQUERY', 'joborder', 'eq_ref', 'PRIMARY,order1', 'PRIMARY', '4', 'opencats.candidate_joborder.joborder_id', '1', ''
'2', 'DEPENDENT SUBQUERY', 'company', 'eq_ref', 'PRIMARY,company1,comp1', 'PRIMARY', '4', 'opencats.joborder.company_id', '1', 'Using where'

我认为是缓慢的部分。

SELECT CONCAT(
'<a href="index.php?m=joborders&amp;a=show&amp;jobOrderID=',
joborder.joborder_id,
'" title="',
joborder.title,
' (',
company.name,
')">',
candidate_joborder_status.short_description,
'</a>'
)
FROM
candidate_joborder
LEFT JOIN candidate_joborder_status
ON candidate_joborder_status.candidate_joborder_status_id = candidate_joborder.status
LEFT JOIN joborder
ON joborder.joborder_id = candidate_joborder.joborder_id
LEFT JOIN company
ON joborder.company_id = company.company_id
WHERE
candidate_joborder.candidate_id = candidate.candidate_id
ORDER BY
candidate_joborder.date_modified DESC
LIMIT 1
) AS lastStatus

我的问题是“我可以采取什么措施来加快查询速度”?数据库上只有 8000 行,并且有大量的服务器资源。这些表是 MyISAM,我已经尝试添加索引,您可以在说明中看到一些正在使用的索引,但是我认为索引并没有太大帮助,因为看起来使这个速度变慢的是 concat、filesort、temp 表(使用没有索引)和可能的三重连接。

这是我的第一篇文章,请原谅格式。我会在发布后尝试编辑它,看看它的外观。

谢谢

【问题讨论】:

SELECT SQL_CALC_FOUND_ROWS candidate.candidate_id AS candidateID, candidate.candidate_id AS exportID, candidate.is_hot AS isHot, candidate.date_modified AS dateModifiedSort, candidate.date_created AS dateCreatedSort, .... GROUP BY candidate.candidate_id 是一个无效的 ANSI SQL 查询,如果 sql-mode ONLY_FULL_GROUP_BY 关闭,它在 mysql 上运行。但无效查询会为未在 GROUP BY 中命名的列生成无效结果。psce.com/en/blog/2012/05/15/… 【参考方案1】:

您也可以索引临时表,这可能会提高性能,并尽量避免文件排序。另一个可以帮助您的资源是 procedure_analysis 选项。它将帮助您创建适当的变量类型。

在此处查找更多信息: https://dev.mysql.com/doc/refman/5.7/en/procedure-analyse.html

【讨论】:

【参考方案2】:

感谢您提供的信息,我安装了 mariadb 10.1,现在一切正常。它在 5.5 centos7 上

【讨论】:

【参考方案3】:
SELECT  CONCAT( '<a href="index.php?m=joborders&amp;a=show&amp;jobOrderID=',
                j.joborder_id, '" title="', j.title, 
                ' (', co.name, ')">',
                cjs.short_description, '</a>' 
              )
    FROM  candidate_joborder AS cj
    LEFT JOIN  candidate_joborder_status AS cjs
          ON cjs.candidate_joborder_status_id = cj.status
    LEFT JOIN  joborder AS j
          ON j.joborder_id = cj.joborder_id
    LEFT JOIN  company AS co
          ON j.company_id = co.company_id
    WHERE  cj.candidate_id = c.candidate_id
    ORDER BY  cj.date_modified DESC
    LIMIT  1 

cj 需要INDEX(candidate_id, date_modified)

    WHERE  candidate.site_id = 1
    GROUP BY  candidate.candidate_id
    ORDER BY  dateModifiedSort DESC

candidate 需要INDEX(site_id, candidate_id)

注意:INDEX(a,b) INDEX(a), INDEX(b) 相同。

【讨论】:

以上是关于使用 concat 和 filesort 时 mysql 查询慢的主要内容,如果未能解决你的问题,请参考以下文章

从查询执行中删除 using temporary 和 Filesort

技术微博 - 4

MySQL 使用 Filesort 和 Query 很慢?

使用 LEFT JOIN 和 ORDER BY...LIMIT 查询慢,使用 Filesort

MySQL 调优 —— Using filesort

说说explain中的Using filesort