加入以奇怪的顺序进行;弄乱ORDER BY?

时间:2017-02-15 05:56:16

标签: mysql join sql-order-by query-optimization explain

假设我有三个表 - 用户,服务器和付款。每个用户可以拥有多个服务器,每个服务器可以有多个付款。我们还要说,我想查找最近的付款,并获取有关这些付款附加到的服务器/客户的信息。这是一个可以执行此操作的查询:

SELECT *
FROM payments p
JOIN customers c ON p.custID = c.custID
JOIN servers s ON s.serverID = p.serverID
WHERE c.hold = 0
    AND c.archive = 0
ORDER BY p.paymentID DESC
LIMIT 10;

问题是当我在这个查询上运行EXPLAIN时,我得到了这个:

id   select_type   table   type   possible_keys            key                key_len   ref                 rows     Extra
1    SIMPLE        c       ref    PRIMARY,hold_archive     hold_archive       3         const,const         28728    Using where; Using index; Using temporary; Using filesort
1    SIMPLE        p       ref    custID                   custID             5         customers.custID    3        Using where
1    SIMPLE        s       eq_ref PRIMARY                  PRIMARY            4         payments.serverID   1        Using index

问题是查询需要一段时间才能运行。如果我删除ORDER BY它会变快10倍。但我需要ORDER BY。当我删除ORDER BY时,这是EXPLAIN:

id   select_type   table   type   possible_keys            key                key_len   ref                 rows     Extra
1    SIMPLE        c       ref    PRIMARY,hold_archive     hold_archive       3         const,const         28728    Using where; Using index
1    SIMPLE        p       ref    custID                   custID             5         customers.custID    3        Using where
1    SIMPLE        s       eq_ref PRIMARY                  PRIMARY            4         payments.serverID   1        Using index

因此,这里的最大区别是Extra列中缺少“Using temporary”和“Using filesort”。

在这种情况下,似乎原因是我正在执行ORDER BY的列不是EXPLAIN中的第一列。

另一个观察。如果我删除其中一个WHERE子句(同时保持ORDER BY),它会同步加速,但我需要两个WHERE。这是一个例子说明:

id   select_type   table   type   possible_keys            key                key_len   ref                 rows     Extra
1    SIMPLE        p       index  custID,serverID          PRIMARY            4         NULL                10       Using where
1    SIMPLE        c       eq_ref PRIMARY,hold_archive     PRIMARY            4         payments.custID     1        Using where
1    SIMPLE        s       eq_ref PRIMARY                  PRIMARY            4         payments.serverID   1        Using index

这里ORDER BY列/是在EXPLAIN的第一列上完成的。但是为什么MySQL会重新安排表格加入的顺序,我怎么能这样做呢?所以它不会这样做?您可以在MySQL中强制索引,但它似乎不是那样的帮助..

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

快10倍 - 它可以找到"任何10行"比#34;找到所有可能的行,对它们进行排序,然后提供10"。

WHEREORDER BY点击不同的列很难优化。

付款的百分比是多少hold=0 and archive=0?这听起来像一个小百分比?每个表中有多少行?

还有什么需要INDEX(hold, archive)吗?如果没有,摆脱它。这似乎只会造成麻烦。

如果hold=0 and archive=0很常见,那么您希望执行与第3 EXPLAIN一样 - 按扫描payments降序排列。由于它们中的大多数与WHERE匹配,因此在查找10个匹配行之前,通常需要打不超过10行。

另一个解决方案(除了删除索引)是在查询中将JOIN更改为STRAIGHT_JOIN。这告诉优化程序您更了解,并且应先payments扫描customersarchive=1秒。如果我的上一段适用,这种方法很有效。

但是,如果您查找Info.plist,那么查询会搞砸(通过缓慢)。