2013-11-03 33 views
1

我有一個包含任務的表的數據庫。任務有一個生命週期。任務生命週期的狀態可能會改變。這些狀態轉換存儲在一個單獨的表tasktransitions中。 現在我寫了一個查詢來查找所有打開/重新打開的任務和最近更改的任務,但我已經看到執行時間變得很長(> 0.5s)的任務數量很少(< 1000)。慢查詢。錯誤的數據庫結構?

任務

+-------------+---------+------+-----+---------+----------------+ 
| Field  | Type | Null | Key | Default | Extra   | 
+-------------+---------+------+-----+---------+----------------+ 
| taskid  | int(11) | NO | PRI | NULL | auto_increment | 
| description | text | NO |  | NULL |    | 
+-------------+---------+------+-----+---------+----------------+ 

Tasktransitions

+------------------+-----------+------+-----+-------------------+----------------+ 
| Field   | Type  | Null | Key | Default   | Extra   | 
+------------------+-----------+------+-----+-------------------+----------------+ 
| tasktransitionid | int(11) | NO | PRI | NULL    | auto_increment | 
| taskid   | int(11) | NO | MUL | NULL    |    | 
| status   | int(11) | NO | MUL | NULL    |    | 
| description  | text  | NO |  | NULL    |    | 
| userid   | int(11) | NO |  | NULL    |    | 
| transitiondate | timestamp | NO |  | CURRENT_TIMESTAMP |    | 
+------------------+-----------+------+-----+-------------------+----------------+ 

查詢

SELECT tasks.taskid,tasks.description,tasklaststatus.status 
FROM tasks 
LEFT OUTER JOIN 
(
    SELECT tasktransitions.taskid,tasktransitions.transitiondate,tasktransitions.status 
    FROM tasktransitions 
    INNER JOIN 
    (
     SELECT taskid,MAX(transitiondate) AS lasttransitiondate 
     FROM tasktransitions 
     GROUP BY taskid 
    ) AS tasklasttransition ON tasklasttransition.lasttransitiondate=tasktransitions.transitiondate AND tasklasttransition.taskid=tasktransitions.taskid 
) AS tasklaststatus ON tasklaststatus.taskid=tasks.taskid 
WHERE tasklaststatus.status IS NULL OR tasklaststatus.status=0 or tasklaststatus.transitiondate>'2013-09-01'; 

更可讀的,上面的查詢的描述性較差版本:

SELECT t.taskid, t.description,ls.status 
FROM tasks AS t 
LEFT OUTER JOIN 
(
    SELECT tt.taskid, tt.transitiondate, tt.status 
    FROM tasktransitions AS tt 
    INNER JOIN 
    (
     SELECT taskid,MAX(transitiondate) AS transitiondate 
     FROM tasktransitions 
     GROUP BY taskid 
    ) AS lt USING (taskid,transitiondate) 
) AS ls USING (taskid) 
WHERE ls.status IS NULL OR ls.status=0 or ls.transitiondate>'2013-09-01'; 

我想知道如果數據庫結構是最好的選擇性能明智。可以添加索引幫助嗎?我已經嘗試添加一些,但我沒有看到很大的改進。

+-----------------+------------+----------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table   | Non_unique | Key_name  | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-----------------+------------+----------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| tasktransitions |   0 | PRIMARY  |   1 | tasktransitionid | A   |   896 |  NULL | NULL |  | BTREE  |   |    | 
| tasktransitions |   1 | taskid_date_ix |   1 | taskid   | A   |   896 |  NULL | NULL |  | BTREE  |   |    | 
| tasktransitions |   1 | taskid_date_ix |   2 | transitiondate | A   |   896 |  NULL | NULL |  | BTREE  |   |    | 
| tasktransitions |   1 | status_ix  |   1 | status   | A   |   3 |  NULL | NULL |  | BTREE  |   |    | 
+-----------------+------------+----------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

其他建議?

+0

澄清 - 目標是選擇所有打開或重新打開或最近更新的任務? – fracz

+1

關於表別名的好處是,它們可以防止SQL走出頁面的RHS。例如,您可以指定'FROM Tasks AS K',然後使用'K.TaskID'而不是'tasks.taskid',更重要的是'FROM TaskTransitions AS T',然後使用'T.TransitionDate'而不是'TaskTransitions .TransitionDate「(您可以根據自己的喜好忽略大小寫)。查詢你必須水平滾動才能看到所說的其他內容是痛苦的。 –

+0

你有沒有試圖將你的查詢分成兩個UNION結果?具體來說,擺脫'LEFT JOIN'來記錄'status = 0或transitiondate>'的記錄。然後將'UNION'轉換爲不存在任務轉換的LEFT JOIN查詢(即'status IS NULL')_第二個查詢應該是一個更簡單的LEFT JOIN,因爲您不需要查找最大(日期)權限嗎?_ – AgRizzo

回答

0

未經測試,不確定這是否是您的目標,但只使用一個子查詢。

SELECT 
    tasks.taskid, tasks.description, 
    (SELECT MAX(transitiondate) 
    FROM tasktransitions WHERE tasktransitions.taskid=tasks.id) lasttransitiondate 
FROM tasks 
LEFT JOIN tasktransitions tt ON tt.taskid = tasks.id 
WHERE tt.tasktransitionid IS NULL 
    OR tt.tasktransitionid = 0 
    OR tt.transitiondate > '2013-09-01'; 

爲了避免子查詢的一切,你可以通過使用觸發器在插入到tasktransitions每跳變變化添加last_trasition_id外鍵tasks表並進行更新。

+0

This查詢不會執行原始查詢所做的相同操作。它不尋找最新的轉換狀態。該查詢連接所有轉換,然後檢查一個是否爲0,而不是最新的。 ps:我認爲你的意思是'tt.status是NULL'而不是'tt.tasktransitionid是NULL' – Tin

+0

你是對的。但是如何增加一列保存這些信息呢?這會加快查詢速度。任務的當前狀態似乎很自然是任務的屬性,如果經常需要 - 不應該在這種複雜的查詢中實時計算。 – fracz