为什么这个 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.type
和 customers.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 版本性能下降的原因。
我有很大的客户数据库。在我添加 ORDER BY
之前,这个查询是可以的。如何优化我的查询速度?
$sql = "SELECT * 来自客户 LEFT JOIN ids ON customer_ids.customer_id = customers.customer_id AND ids.type = '10' 订购 customers.name 限额 10";
ids.type
和 customers.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 版本性能下降的原因。