为什么这个 INNER JOIN/ORDER BY mysql 查询这么慢?

Why is this INNER JOIN/ORDER BY mysql query so slow?

我有很大的客户数据库。在我添加 ORDER BY 之前,这个查询是可以的。如何优化我的查询速度?

$sql = "SELECT * 来自客户
LEFT JOIN ids ON customer_ids.customer_id = customers.customer_id AND ids.type = '10'
订购 customers.name 限额 10";

ids.typecustomers.name 是我的索引

解释查询

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE customers ALL NULL NULL NULL NULL 955 使用临时;使用文件排序
1 SIMPLE ids ALL type NULL NULL NULL 3551 Using where;使用连接缓冲区(块嵌套循环)

(我假设您打算输入 ids.customer_id = customer.customer_id 而不是 customer_ids.customer_id)

没有 ORDER BY mysql 抓取类型 10(索引)的前 10 个 id,为他们查找客户,然后完成。 (请注意,这里的 LEFT JOIN 实际上是一个 INNER JOIN,因为连接条件只适用于在两个 tables 中都有匹配的行)

使用 ORDER BY mysql 可能会检索 all type=10 个客户,然后按名字对他们进行排序以找到前 10 个。

您可以通过非规范化客户 table(将类型复制到客户记录中)或创建映射 table 来保存 customer_id, name, type 元组来加快速度。无论哪种情况,都在 (type, name) 上添加索引。如果使用映射 table,请使用它与客户和 ID 进行三向连接。

如果 type=10 相当常见,您还可以强制查询按名称遍历客户 table 并使用 STRAIGHT JOIN 检查每个客户的类型。它不会像复合索引那样快,但会比拉出所有匹配项更快。

并且如上所述,运行 对您的查询进行 EXPLAIN 以查看 mysql 正在使用的查询计划。

左边是问题所在。通过说 LEFT JOIN,您暗示某些 customers 可能在 ids 中没有相应的行。并且您愿意接受字段的 NULL 来代替 ids 行。

如果不是这样,则删除 LEFT。然后确保您在 ids 上有一个索引 开始 type。此外,customers 必须有一个以 customer_id 开头的索引(可能是 PRIMARY KEY)。有了这些,优化器可以从 ids 开始,更早地过滤 type,从而减少工作量。

但是,在进行排序之前它仍然必须收集大量行 (ORDER BY);只有这样它才能交付 10 (LIMIT).

当你这样做的时候,将 INDEX(customer_id) 添加到 ids -- 这就是 LEFT 版本性能下降的原因。