MySQL非常慢的查询

时间:2014-01-13 16:52:54

标签: mysql performance

我正在尝试了解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

数据库服务器默认使用MyISAM,因此大多数模式(包括此模式)都是MyISAM。

我也意识到文字搜索(status=Donestatus LIKE 'Done')正在为查询添加很多内容。

EDIT1:

# 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

2 个答案:

答案 0 :(得分:3)

我会编写如下查询,但为了帮助优化,请在表格上设置覆盖索引。

员工表 - 索引(状态,employeeID) 任务表 - 索引(employeeid,templateid,status)

通过第一次加入,您将获得资格预审,将第一项任务视为“完成”状态。

第二个联接正在寻找您感兴趣的尚未完成的OTHER任务。

执行子查询(尤其是相关的子查询)可能会更难以提高性能。通过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' 

答案 1 :(得分:2)

您的第一个更改应该是在task上创建涵盖statustemplateId列的索引:

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应该只是status,就像第二个子查询一样。