2014-01-13 118 views
1

我想了解優化到MySQL,臺發動機以及何時使用它們,等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')正在增加很多查詢。

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 
+0

你對錶格有什麼索引?請您提供'SHOW CREATE TABLE employee'和'SHOW CREATE TABLE task'的輸出結果# – Jon

回答

3

我會寫如下查詢,但爲了幫助優化,在表上有一個覆蓋索引。

Employee表 - 指數(地位,僱員) 任務表 - 上(僱員,templateid,狀態)

通過指數的首次加入,你對資格預審獲得第一個任務作爲「完成「 狀態。

第二次連接正在尋找您感興趣的NOT DONE任務。

做子查詢(尤其是相關的子查詢)可能會更難性能。通過加入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' 
+0

這是一個很大的改進,0.015s。感謝您提供了一種查看子查詢的不同方式......我沒有想過以這種方式加入它們。 –

+0

@丹尼爾V。,只是有點快點?? ...高興它工作:) – DRapp

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像第二子查詢。

+0

欣賞輸入...第一個狀態實際上是一個錯字,謝謝。我添加了索引,並會在查詢時間中返回不同的報告。 –

+0

另外,外部的SELECT,em.employeeId <>'Not Done'應該是em.status <'Not Done'> –

+0

建議更改後,查詢時間降至34.5秒。 –