多个左联接优化

时间:2018-07-25 11:25:31

标签: mysql sql

表格:

  • 员工
  • employee_orgn
    • 联合主键(employee_id,orgn_id)
    • 两个索引:key1:employee_id,index2:orgn_id
  • orgn

有些员工没有组织。

sql:

explain SELECT DISTINCT
    e.*
FROM
    employee e
        LEFT JOIN
    employee_orgn eo ON eo.employee_id = e.id
        LEFT JOIN
    orgn o ON o.id = eo.orgn_id
WHERE
    e.state != 'deleted'
        AND e.state != 'hidden'
        AND (o.state != 'hidden' OR o.state IS NULL)
ORDER BY e.id DESC

解释:

| id   | select_type    |  table | type | possible_keys | key  | key_len | ref  | rows | Extra |

| 1        | SIMPLE     |   e    |all        | NULL     |   NULL    |NULL        | NULL      |   12792    |Using where;USing tempory;Using filesort       | 

| 1        | SIMPLE     |   eo    |index        | PRIMARY     |   idx_orgn_id    |8        | NULL     |   13226  |Using index:Distinct  | 

| 1        | SIMPLE     |   o    |eq_ref        | PRIMARY      |   PRIMARY    |8        | eo.orgn_id      |   1    |Using where:Distinct           | 

问:

  1. 在这里左联接,mysql嵌套循环查询10个数量级8?
  2. 为什么有临时表,为什么排序是文件排序?
  3. 为什么第二行是覆盖索引
  4. 我希望有人能解释这个解释结果并优化分析。

谢谢。

2 个答案:

答案 0 :(得分:0)

我建议重写查询-摆脱select distinct。我认为这是您想要的逻辑:

SELECT e.*
FROM employee e
WHERE e.state not in ('deleted', 'hidden')
      NOT EXISTS (SELECT 1
                  FROM employee_orgn eo JOIN
                       orgn o
                       ON o.id = eo.orgn_id AND o.state = 'hidden'
                  WHERE eo.employee_id = e.id
                 )
ORDER BY e.id DESC;

对于此查询,您需要在employee_orgn(employee_id, orgn_id)orgn(id, state)上建立索引。

答案 1 :(得分:0)

您不应在WHERE子句中保留联接的表上放置条件。而是将它们放在ON子句中。然后,您无需使用OR o.state IS NULL,这会导致优化程序出现问题。

SELECT DISTINCT
    e.*
FROM
    employee e
        LEFT JOIN
    employee_orgn eo ON eo.employee_id = e.id
        LEFT JOIN
    orgn o ON o.id = eo.orgn_id AND o.state != hidden
WHERE
    e.state NOT IN ('deleted', 'hidden')
ORDER BY e.id DESC