需要优化的选择查询

时间:2016-07-15 09:37:22

标签: mysql database query-optimization

考虑以下架构:

Tables: Tasks (tid, jobid, status, name)
        Jobs(jobid, submitTime)

这里我可以有多个任务表行和一个jobid。现在我想从Tasks表中获取所有行,使得它们的状态= 5,而具有相同jobid的所有其他行也应该是5。

例如:我在任务中有5行,前2个有jobid = 1,状态= 5,最后3个有jobid = 2,两个有status = 5,1有status = 4。我的查询应该只返回jobid = 1的前两行,因为jobid = 1的所有行的status = 5。不应返回jobid = 2的行,因为jobid = 2的一行的status = 4。

假设我在Tasks表中有300K行,我需要帮助构建优化查询。

mysql> select * from task;
+--------+-------+--------+----------------------+
| taskid | jobid | status | name                 |
+--------+-------+--------+----------------------+
|      1 |     1 |      5 | Task 1, Job 1        |
|      2 |     1 |      5 | Task 2, Job 1        |
|      3 |     2 |      5 | Task 3, Job 2        |
|      4 |     2 |      5 | Task 4, Job 2        |
|      5 |     2 |      4 | Task 5, Job 2 status |
+--------+-------+--------+----------------------+
5 rows in set (0.00 sec)

mysql> select * from job;
+-------+---------------------+
| jobid | time                |
+-------+---------------------+
|     1 | 2016-07-15 15:13:42 |
|     2 | 2016-07-15 15:13:44 |
+-------+---------------------+

我需要的输出:

+--------+-------+--------+----------------------+
| taskid | jobid | status | name                 |
+--------+-------+--------+----------------------+
|      1 |     1 |      5 | Task 1, Job 1        |
|      2 |     1 |      5 | Task 2, Job 1        |

2 个答案:

答案 0 :(得分:0)

SELECT *
FROM tasks t
WHERE t.`status` = 5
AND NOT EXISTS (
    SELECT 1
    FROM tasks tt
    WHERE t.jobid = tt.jobid
    AND tt.`status` <> 5
)

输出:

+-----+-------+--------+---------------+
| tid | jobid | status | name          |
+-----+-------+--------+---------------+
|   1 |     1 |      5 | Task 1, Job 1 |
|   2 |     1 |      5 | Task 2, Job 1 |
+-----+-------+--------+---------------+
2 rows in set

最重要的是考虑在statusjobid列添加索引:

ALTER TABLE `tasks` 
    ADD INDEX `status_IDX` (`status`),
    ADD INDEX `jobid_IDX` (`jobid`);

或者更好的是两个字段中只有一个复合索引:

ALTER TABLE `tasks` 
    ADD INDEX `composite_IDX` (`status`,`jobid`);

您将选择哪个索引取决于您将对该表执行哪种查询。在这种特殊情况下,复合材料是更好的选择。

答案 1 :(得分:0)

您可以使用LEFT JOIN对同一个表执行此操作,该表将加入status <> 5的所有记录。 然后,您可以排除从此JOIN获得结果的任何记录。

事实上,在statusjobid上添加索引可以提高效果。

SELECT t.taskid, t.jobid, t.status, t.name
FROM task t
LEFT JOIN task t2
    ON t.jobid = t2.jobid 
    AND t.taskid  <> t.taskid 
    AND t.status <> 5
WHERE t.status = 5
AND t2.taskid IS NULL
GROUP BY t.taskid

让我知道这是否有效! 祝你好运:)