MySQL加入OR条件导致的性能问题

时间:2018-07-09 13:59:58

标签: mysql

有人能想到一种更有效的方式编写此查询,因为它在我运行时会不断超时吗?

SELECT 
orders.OrderKey,
shipout.primary_subcategory
FROM
orders
    INNER JOIN
orderitems ON orderitems.OrderID = orders.OrderID
    INNER JOIN
subjects ON subjects.SubjectID = orderitems.SubjectID
    INNER JOIN
subjectdetails ON subjectdetails.SubjectID = subjects.SubjectID
    INNER JOIN
shipout ON shipout.id_invoice = subjects.SubjectKey
        OR shipout.id_invoice = orders.OrderKey
GROUP BY orders.orderkey

如果我删除OR条件,它将在0.2秒内完成。即使我用orders表而不是subjects表切换了最后一个联接,它也会在0.1秒内完成。

shipout ON shipout.id_invoice = orders.OrderKey
GROUP BY orders.orderkey

但是当我尝试同时使用OR将两者同时加入时,它会超时。这是解释:

+----+-------------+----------------+--------+-----------------------------------------+----------------------+---------+--------------------------+--------+----------------------------------------------------+
| id | select_type |     table      |  type  |              possible_keys              |         key          | key_len |           ref            |  rows  |                       Extra                        |
+----+-------------+----------------+--------+-----------------------------------------+----------------------+---------+--------------------------+--------+----------------------------------------------------+
|  1 | SIMPLE      | shipout        | ALL    |                                         |                      |         |                          |  10658 | Using temporary; Using filesort                    |
|  1 | SIMPLE      | subjectdetails | index  | PRIMARY                                 | SubjectDetails_ID    |     768 |                          | 455446 | Using index; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | subjects       | eq_ref | PRIMARY,Subjects_SubjectKey             | PRIMARY              |       4 | subjectdetails.SubjectID |      1 |                                                    |
|  1 | SIMPLE      | orderitems     | ref    | OrderItems_OrderID,OrderItems_SubjectID | OrderItems_SubjectID |       5 | subjectdetails.SubjectID |      1 |                                                    |
|  1 | SIMPLE      | orders         | eq_ref | PRIMARY,Orders_OrderKey                 | PRIMARY              |       4 | orderitems.OrderID       |      1 | Using where                                        |
+----+-------------+----------------+--------+-----------------------------------------+----------------------+---------+--------------------------+--------+----------------------------------------------------+

要注意的一件事是,我不是数据库管理员,因此无法索引表。看起来似乎是subjectdetails,但是我不确定出货。

2 个答案:

答案 0 :(得分:3)

对当前查询进行UNION重写。
正确的索引编制也可能会提高性能。

查询

SELECT 
orders.OrderKey,
shipout.primary_subcategory
FROM
orders
    INNER JOIN
orderitems ON orderitems.OrderID = orders.OrderID
    INNER JOIN
subjects ON subjects.SubjectID = orderitems.SubjectID
    INNER JOIN
subjectdetails ON subjectdetails.SubjectID = subjects.SubjectID
    INNER JOIN
shipout ON shipout.id_invoice = subjects.SubjectKey
GROUP BY orders.orderkey

UNION ALL

SELECT 
orders.OrderKey,
shipout.primary_subcategory
FROM
orders
    INNER JOIN
orderitems ON orderitems.OrderID = orders.OrderID
    INNER JOIN
subjects ON subjects.SubjectID = orderitems.SubjectID
    INNER JOIN
subjectdetails ON subjectdetails.SubjectID = subjects.SubjectID
    INNER JOIN
shipout ON shipout.id_invoice = orders.OrderKey
GROUP BY orders.orderkey
  

要注意的一件事是,我不是数据库管理员,所以无法索引   桌子

但是仍然请数据库管理员提供建议和索引。

答案 1 :(得分:1)

您可以尝试像这样重写最后一个JOIN:

shipout ON shipout.id_invoice = COALESCE(subjects.SubjectKey, orders.OrderKey)

像这样,消除了OR,但连接了相同的行。仅当subject.SubjectKey /orders.OrderKey为NULL时,此方法才有效;如果在创建JOIN时不是,则为NULL,但是在不知道确切数据结构的情况下很难分辨。