通过在MySQL中使用JOIN优化这些嵌套的IN语句

时间:2019-04-03 13:42:02

标签: mysql join where

我正在编写一个查询,以从表中排除某些雇员组。假设我有表1,transaction_details,其中包含我要选择的信息。表2,employee_task_associations将每个员工映射到他们在特定日期分配给的任务。它具有一个名为employee_id的字段,以及一个名为map_id的字段,它是不同任务的ID。该表是一个关联表,因此表1和3可以具有多对多关系。表3,employee_tasks,列出了员工可以执行的所有任务。

我已经编写了此查询,该查询是功能强大但未优化的查询:

SELECT someInfo FROM transaction_details TD
WHERE TD.employee_id NOT IN
  (SELECT employee_id from employee_task_associations ETA
    WHERE map_id IN
      (SELECT id FROM employee_tasks ET
       WHERE ET.taskName = "The task I want to exclude"))

虽然可行,但它将运行多个查询。我想通过用JOINS替换嵌套的NOT IN和IN语句来加快处理速度。

我知道我可以将下面的四行替换为以下内容:

SELECT employee_id FROM employee_task_assocations ETA
  LEFT OUTER JOIN employee_tasks ET
    ON ETA.map_id = ET.id
    WHERE ET.taskName = "The task I want to exclude"

这将返回已执行此任务的员工的所有ID的列表。我想通过使用JOIN而不是子查询将这些从我的SELECT语句中从transaction_details中排除。我已经尝试使用ETA.id IS NULL的LEFT OUTER JOIN OUTIN JOIN,但这是行不通的。在这种情况下,如何使用JOIN排除某些员工?

2 个答案:

答案 0 :(得分:1)

您似乎在初始查询上接近了,但是为什么不加入NOT IN查询并获得不同的员工...类似

SELECT 
      TD.someInfo 
   FROM 
      transaction_details TD
   WHERE 
      TD.employee_id NOT IN
         (SELECT DISTINCT
                employee_id 
             from 
                employee_task_associations ETA
                   JOIN employee_tasks ET
                      ON ETA.map_id = ET.ID
                      AND ET.taskName = "The task I want to exclude")

答案 1 :(得分:0)

您似乎认为外部联接比子查询更高效,但这不是事实。这完全取决于SQL计划程序,SQL优化器,现有索引,表统计信息,并最终取决于数据库引擎提供的数据运算符。

此外,您应该考虑到,在解析之后,查询进入转换阶段,在该阶段,数据库引擎可以自由地以更有效的方式重写查询。这意味着即使在编写子查询的情况下,实际上也可以使用外部联接来执行查询。之后,[重写的]查询进入查询计划器,然后进入SQL优化器。

对其进行优化的唯一方法是获取所有查询选项的执行计划并进行比较。