1

タスクを含むテーブルを持つデータベースがあります。タスクにはライフサイクルがあります。タスクのライフサイクルのステータスは変更される可能性があります。これらの状態遷移は、別のテーブル tasktransitions に格納されます。ここで、開いている/再開されたすべてのタスクと最近変更されたタスクを検索するクエリを作成しましたが、かなり少数のタスク (<1000) で実行時間が非常に長く (>0.5 秒) なっていることが既にわかります。

タスク

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

タスク遷移

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

他の提案はありますか?

4

1 に答える 1

0

テストされておらず、これが目的であるかどうかはわかりませんが、サブクエリを 1 つだけ使用します。

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

于 2013-11-03T10:13:25.247 に答える