假设我有三个表 - 用户,服务器和付款。每个用户可以拥有多个服务器,每个服务器可以有多个付款。我们还要说,我想查找最近的付款,并获取有关这些付款附加到的服务器/客户的信息。这是一个可以执行此操作的查询:
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中强制索引,但它似乎不是那样的帮助..
有什么想法吗?
答案 0 :(得分:1)
快10倍 - 它可以找到"任何10行"比#34;找到所有可能的行,对它们进行排序,然后提供10"。
让WHERE
和ORDER BY
点击不同的列很难优化。
付款的百分比是多少hold=0 and archive=0
?这听起来像一个小百分比?每个表中有多少行?
还有什么需要INDEX(hold, archive)
吗?如果没有,摆脱它。这似乎只会造成麻烦。
如果hold=0 and archive=0
很常见,那么您希望执行与第3 EXPLAIN
一样 - 按扫描payments
降序排列。由于它们中的大多数与WHERE
匹配,因此在查找10个匹配行之前,通常需要打不超过10行。
另一个解决方案(除了删除索引)是在查询中将JOIN
更改为STRAIGHT_JOIN
。这告诉优化程序您更了解,并且应先payments
扫描customers
,archive=1
秒。如果我的上一段适用,这种方法很有效。
但是,如果您查找Info.plist
,那么查询会搞砸(通过缓慢)。