【问题标题】:Need optimized select query需要优化的选择查询
【发布时间】:2016-07-15 09:37:22
【问题描述】:

考虑以下架构:

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

在这里,我可以使用一个 jobid 来处理多个任务表行。现在我想从 Tasks 表中获取所有行,这样它们的 status=5 并且所有其他具有相同 jobid 的行也应该是 5。

例如:我在任务中有 5 行,前 2 行 jobid=1 和 status=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        |

【问题讨论】:

  • 请编辑您的问题以将输入和所需输出显示为表格。我无法将您的描述翻译成表格形式。
  • jobs 表与您的问题有何关联?
  • @TimBiegeleisen 已添加
  • @mitkosoft 您可以说它不相关,并将 jobid 假定为独立值。但我的查询需要,如果两行具有相同的 jobid 但其中一个具有状态!=5,则不应从输出中返回这两行。
  • 似乎一个简单的WHERE 子句应该可以工作。如果不是,那么您的示例不会显示查询中的更多复杂性。在那里扔一些索引,然后就可以了。

标签: mysql database query-optimization


【解决方案1】:
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`);

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

【讨论】:

  • 不,最好这样:INDEX(jobid, status)INDEX(status)
【解决方案2】:

您可以对同一个表使用LEFT JOIN 来执行此操作,这将连接到具有status &lt;&gt; 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

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

【讨论】:

  • 这需要INDEX(jobid)INDEX(status, taskid)
猜你喜欢
  • 2022-07-19
  • 2017-01-06
  • 2023-03-12
  • 2014-02-15
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
相关资源
最近更新 更多