繁体   English   中英

MySQL极慢的查询

[英]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=Donestatus 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上创建一个索引,该索引同时包含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应该像第二tsk.status查询一样处于status

暂无
暂无

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

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