简体   繁体   English

MySQL极慢的查询

[英]MySQL Extremely Slow Query

I am trying to learn about optimizations to MySQL, table engines and when to use them, etc. 我正在尝试学习对MySQL,表引擎以及何时使用它们等的优化。

I have a query that is running up against the time-out limit of 10 minutes and which needs to complete in seconds because its function is a user-generated report. 我有一个查询,该查询的超时限制为10分钟,由于它的功能是用户生成的报告,因此需要在几秒钟内完成。

The Query: 查询:

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'
)

Explain: 说明:

# 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

The DB server uses MyISAM as default, so most schemas including this one are MyISAM. DB服务器默认使用MyISAM,因此包括该模式在内的大多数模式都是MyISAM。

I also realize that the text searches ( status=Done or status LIKE 'Done' ) are adding a lot to the query. 我还意识到,文本搜索( status=Donestatus LIKE 'Done' )给查询增加了很多。

EDIT1: 编辑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

EDIT 2: 编辑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

I would write the query as below, but to help the optimization, have a covering indexes on your tables. 我将按以下方式编写查询,但是为了帮助优化,表上应包含​​覆盖索引。

Employee table -- index on ( status, employeeID ) Task table -- index on ( employeeid, templateid, status ) 员工表-(状态,employeeID)上的索引任务表-(employeeid,templateid,状态)上的索引

By the first join, you are prequalifying to get the first task as a "Done" status. 通过首次加入,您将有资格获得第一个任务为“完成”状态。

The second join is looking for the OTHER task you are interested in that is NOT Done. 第二个联接正在寻找您感兴趣的其他任务“未完成”。

Doing subqueries (especially correlated sub queries) can be harder on performance. 进行子查询(尤其是相关子查询)可能会提高性能。 By doing a JOIN, it's either there or its not... 通过执行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' 

Your first change should be to create an index on task that covers both the status and templateId columns: 您的第一个更改应该是在task上创建一个索引,该索引同时包含statustemplateId列:

ALTER TABLE task ADD INDEX (status, templateId);

That'll prevent the full-table scans of 61326 rows each time that table is accessed in your query. 这样可以防止在查询中每次访问该表时对61326行进行全表扫描。

Also, it looks like you might have made a typo here: 另外,您似乎在这里输入过错误:

SELECT employeeId FROM task
WHERE templateId 
IN ( '5', '6', '7', '8' )
AND tsk.status = 'Done'

That tsk.status should be just status like the 2nd subquery. tsk.status应该像第二tsk.status查询一样处于status

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM