Mysql 以奇怪的顺序进行连接;把订单搞砸了?

Mysql 以奇怪的顺序进行连接;把订单搞砸了?,mysql,join,sql-order-by,query-optimization,explain,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

假设我有三个表——用户、服务器和付款。每个用户可以有多个服务器,每个服务器可以有多个付款。也就是说,我想查找最近的付款,并获取这些付款所附加到的服务器/客户的信息。下面是一个可以执行此操作的查询:

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
问题是查询需要一段时间才能运行。如果我取消订单,它会变为10倍快。但是我需要你的订单。以下是我删除订单时的解释:

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
因此,这里最大的区别在于,额外列中缺少“使用临时”和“使用文件排序”

在本例中,原因似乎是,我正在执行ORDER BY的列不是解释中的第一列

另一个观察。如果我删除其中一个WHERE子句(同时保持顺序),它的速度将类似,但我需要两个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
此处,在解释的第一列上按列/排序。但是为什么MySQL要重新安排表的连接顺序,我如何才能使它不这样做呢?您可以在MySQL中强制使用索引,但这似乎没有什么帮助

有什么想法吗?

快10倍——它可以找到“任意10行”,比“找到所有可能的行,对它们进行排序,然后交付10行”快得多

WHERE
ORDER BY
命中不同的列很难优化

持有=0且存档=0的付款百分比是多少?这听起来像一个小百分比?每个表有多少行

还有什么需要索引(保存、存档)?如果没有,就把它扔掉。这似乎只是在这里制造麻烦

如果
hold=0和archive=0
是常见的,那么您希望执行过程像第三次
EXPLAIN
——即按降序扫描
付款。由于它们中的大多数匹配
,其中
,通常需要点击不超过10行才能找到10个匹配行

另一种解决方案(除去索引之外)是将查询中的
JOIN
更改为
stright\u JOIN
。这会告诉优化器您更清楚,应该首先扫描
付款
,然后扫描
客户
。如果我的前一段适用的话,这很有效


但是,如果您查找
archive=1

这样的问题,那么查询会出错(速度慢),您还需要为所有相关表提供SHOW CREATE TABLE语句快速猜测:如果没有
ORDER by
子句,然后,服务器返回符合条件的前10条记录,并在达到该数字后停止处理。它可能从
customer
表开始,因为该表上有一个过滤器,然后查找相关的
付款
,然后查找匹配的
服务器。效果很好。但是,当您按
添加
订单时,它首先需要列出所有匹配的记录(
c
=>
p
=>
s
),对
paymentID
上的记录进行排序,然后从该列表中从“最低”的记录开始选择前10个记录。