使用 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&a=show&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&a=show&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&a=show&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