[英]MySQL Extremely Slow Query
我正在尝试学习对MySQL,表引擎以及何时使用它们等的优化。
我有一个查询,该查询的超时限制为10分钟,由于它的功能是用户生成的报告,因此需要在几秒钟内完成。
查询:
SELECT em.employeeId, tsk.taskId
FROM employee em INNER JOIN
task tsk
ON tsk.employeeId = em.employeeId
WHERE em.employeeId <> 'Not Done'
AND tsk.employeeId (
SELECT employeeId FROM task
WHERE templateId
IN ( '5', '6', '7', '8' )
AND tsk.status = 'Done'
)
AND tsk.employeeId IN
(
SELECT employeeId FROM task
WHERE templateId IN
( '55', '56', '57', '58' )
AND status = 'Not Done'
)
说明:
# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, PRIMARY, tsk, ALL, , , , , 61326, Using where
1, PRIMARY, em, eq_ref, PRIMARY, PRIMARY, 4, newhire.tsk.employeeId, 1, Using index
3, DEPENDENT SUBQUERY, task, ALL, , , , , 61326, Using where
2, DEPENDENT SUBQUERY, task, ALL, , , , , 61326, Using where
DB服务器默认使用MyISAM,因此包括该模式在内的大多数模式都是MyISAM。
我还意识到,文本搜索( status=Done
或status LIKE 'Done'
)给查询增加了很多。
编辑1:
# Table, Create Table
employee, CREATE TABLE `employee` (
`employeeId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`lastName` varchar(255) NOT NULL,
`firstName` varchar(255) NOT NULL,
`applicantId` varchar(255) NOT NULL,
`fEmployeeId` varchar(255) DEFAULT NULL,
`opId` varchar(255) DEFAULT NULL,
`rehire` tinyint(3) unsigned NOT NULL DEFAULT '0',
`sDate` date DEFAULT NULL,
`oDate` date DEFAULT NULL,
`cDate` date DEFAULT NULL,
`additionalDate` date DEFAULT NULL,
`additionalType` varchar(255) DEFAULT NULL,
`processingDate` date DEFAULT NULL,
`created` datetime NOT NULL,
`recruiterId` int(10) unsigned NOT NULL,
`processorId` int(10) unsigned DEFAULT NULL,
`position` tinyint(3) unsigned NOT NULL DEFAULT '1',
`status` varchar(255) NOT NULL,
`campus` varchar(255) DEFAULT NULL,
`phone` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`requisition` varchar(255) DEFAULT NULL,
`Position` varchar(255) DEFAULT NULL,
`department` varchar(255) DEFAULT NULL,
`jobClass` varchar(255) DEFAULT NULL,
`hiringManager` varchar(255) DEFAULT NULL,
`badge` varchar(255) DEFAULT NULL,
`currentAddress` varchar(255) DEFAULT NULL,
`holding` tinyint(3) unsigned DEFAULT '0',
PRIMARY KEY (`employeeId`)
) ENGINE=MyISAM AUTO_INCREMENT=3959 DEFAULT CHARSET=latin1
编辑2:
# Table, Create Table
task, CREATE TABLE `task` (
`taskId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`templateId` int(10) unsigned NOT NULL,
`employeeId` int(10) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`description` text,
`naAvailable` tinyint(3) unsigned DEFAULT '0',
`fileRequired` tinyint(3) unsigned DEFAULT '0',
`fileHrCatalog` int(10) unsigned DEFAULT NULL,
`quickFileName` varchar(255) DEFAULT NULL,
`fileUploaded` tinyint(3) unsigned DEFAULT '0',
`fileExt` varchar(255) DEFAULT NULL,
`level` tinyint(3) unsigned NOT NULL,
`status` varchar(255) NOT NULL,
`due` date DEFAULT NULL,
`daysDue` int(10) unsigned DEFAULT NULL,
`routeIncentives` tinyint(3) unsigned DEFAULT '0',
`requiresAudit` tinyint(3) unsigned DEFAULT '0',
`auditStatus` varchar(255) DEFAULT NULL,
`auditUser` int(10) unsigned DEFAULT NULL,
`auditDate` datetime DEFAULT NULL,
`stampOption` tinyint(3) unsigned DEFAULT '0',
`done` tinyint(3) unsigned DEFAULT '0',
`doneBy` int(10) unsigned DEFAULT NULL,
`doneWhen` datetime DEFAULT NULL,
`sortOrder` tinyint(3) unsigned NOT NULL DEFAULT '255',
PRIMARY KEY (`taskId`),
KEY `status` (`status`,`templateId`)
) ENGINE=MyISAM AUTO_INCREMENT=176802 DEFAULT CHARSET=latin1
我将按以下方式编写查询,但是为了帮助优化,表上应包含覆盖索引。
员工表-(状态,employeeID)上的索引任务表-(employeeid,templateid,状态)上的索引
通过首次加入,您将有资格获得第一个任务为“完成”状态。
第二个联接正在寻找您感兴趣的其他任务“未完成”。
进行子查询(尤其是相关子查询)可能会提高性能。 通过执行JOIN,它要么在那里,要么不...
SELECT
em.employeeId,
tsk.taskId
FROM
employee em
INNER JOIN task tsk1
ON em.employeeId = tsk1.employeeId
AND tsk1.templateID in ( '5', '6', '7', '8' )
AND tsk1.status = 'Done'
INNER JOIN task tsk2
ON em.employeeId = tsk2.employeeId
AND tsk2.templateID in ( '55', '56', '57', '58' )
AND tsk2.status = 'Not Done'
WHERE
em.status <> 'Not Done'
您的第一个更改应该是在task
上创建一个索引,该索引同时包含status
和templateId
列:
ALTER TABLE task ADD INDEX (status, templateId);
这样可以防止在查询中每次访问该表时对61326行进行全表扫描。
另外,您似乎在这里输入过错误:
SELECT employeeId FROM task
WHERE templateId
IN ( '5', '6', '7', '8' )
AND tsk.status = 'Done'
该tsk.status
应该像第二tsk.status
查询一样处于status
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.