慢查询。错误的数据库结构?

时间:2013-11-03 09:50:55

标签: mysql

我有一个包含任务的表的数据库。任务具有生命周期。任务生命周期的状态可能会发生变化。这些状态转换存储在单独的表taskTransitions中。 现在我编写了一个查询来查找所有打开/重新打开的任务以及最近更改的任务,但我已经看到了相当少的任务(< 1000),执行时间变得非常长(> 0.5s)。

任务

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

还有其他建议吗?

1 个答案:

答案 0 :(得分: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';

要完全避免使用子查询,可以向last_trasition_id表添加tasks外键,并在每次转换更改时使用插入tasktransitions的触发器更新它。