优化 JOIN 查询,哪个 "JOIN" 最好?
Optimize a JOIN query, which "JOIN" would be the best?
我有 2 tables :
Table 项目
ID
ID_ORDER
ID_BOX
NAME
001
2564
123
SPOON_1
002
2564
123
SPOON_2
006
2564
123
SHOES_2
007
2564
123
SHOES_1
003
2565
124
SPOON_1
004
2565
124
SPOON_2
008
2565
124
SHOES_1
009
2565
124
SHOES_2
005
2565
125
SPOON_1
010
2565
125
SHOES_1
Table 说明:
ID_ORDER
NAME
LENGTH
WIDTH
....
2564
SPOON_1
200
20 ...
2564
SPOON_2
300
20 ...
2564
SHOES_1
500
20 ...
2564
SHOES_2
600
20 ...
对象的描述通过 ID_ORDER 和名称链接到项目 table。(不可能有 2 个名称相同的项目,但在同一订单中有不同的描述)。
我发现更快的方法是使用 C#(我比较了所有时间):
我提出请求 SELECT * FROM items WHERE ID_ORDER=2567
,return 是我 List<Item>
。
然后我按名称分组,以在列表中包含项目名称列表:
List listNames=listItems.Select(x=>"'"+x.Name+"'").Distinct().ToList();
我发出第二个请求,将查找所有对应的描述:
string query = "SELECT * FROM description WHERE ID_ORDER=2567 AND NAME IN ("+string.Join(",",listNames)+")";
即使我的订单中有 1000 件商品,但只有 50 件不同的商品,在第一次查询中我 return 所有 1000 件商品,然后在第二次查询中我 return 只有 50 条描述。
所以最后我只需要做类似的事情:
foreach(Item item in listItems)
{
item.Description=listDescriptions.FirstOrDefault(x=>x.Name==item.Name);
}
现在,我试图在一个 SQL 请求中完成所有工作。这是我现在拥有的:
SELECT * FROM items INNER JOIN description
ON (description.ID_ORDER=items.ID_ORDER AND description.NAME=items.NAME)
WHERE ID_ORDER= 2564
据我了解,问题是 SQL 将搜索项目列表,然后将搜索每个项目的描述,并且看起来更多时间,因为描述是大数据。
有没有更快的方法让 SQL 首先读取与我的项目列表对应的所有描述,然后将描述应用于每个项目?我也试过 RIGHT JOIN(我相信它会那样做),但它花费的时间几乎和简单的 JOIN 一样多,使用 C# 仍然是更快的方法。
您可以使用 EXPLAIN 命令,它会让您知道 MySQL 计划如何回答您的查询。您可以使用它来优化您的查询 运行 更快,或者只是为了了解它是如何工作的。参见 https://dev.mysql.com/doc/refman/8.0/en/explain.html
例如:
EXPLAIN SELECT * FROM items INNER JOIN description
ON (description.ID_ORDER=items.ID_ORDER AND description.NAME=items.NAME)
WHERE ID_ORDER=2564
JOIN
包括根据 ON
匹配的 table 和 行。 (或者关系可能隐藏在不属于它们的 WHERE
中。WHERE
应该仅用于过滤。)
LEFT JOIN
包括“左”table 的所有行和“右”table 的任何匹配行,无论它们是否匹配。不匹配的行在列中显示 NULL
。
FROM a LEFT JOIN b ON ... WHERE b.id IS NULL
是用于查找 a
行的模式,对应的 b
行是 missing`。
RIGHT JOIN
是交换了 table 的 LEFT JOIN
。 (别用这个,我脑袋疼。)
CROSS JOIN
具有两个 table 行的所有组合。相当于WHERE
子句中没有ON
,也没有'relationship'。
“commajoin”是旧语法:FROM a,b WHERE a.foo=b.foo
。不要使用它;如果你这样做,本论坛的回复者会打你的手。
关键字 INNER
和 OUTER
不相关并被 MySQL 忽略 。
FULL OUTER JOIN
是 MySQL 不支持的功能和语法。它可以用 JOIN
和 LEFT JOIN
结合 UNION
.
来模拟
我有 2 tables :
Table 项目
ID | ID_ORDER | ID_BOX | NAME |
---|---|---|---|
001 | 2564 | 123 | SPOON_1 |
002 | 2564 | 123 | SPOON_2 |
006 | 2564 | 123 | SHOES_2 |
007 | 2564 | 123 | SHOES_1 |
003 | 2565 | 124 | SPOON_1 |
004 | 2565 | 124 | SPOON_2 |
008 | 2565 | 124 | SHOES_1 |
009 | 2565 | 124 | SHOES_2 |
005 | 2565 | 125 | SPOON_1 |
010 | 2565 | 125 | SHOES_1 |
Table 说明:
ID_ORDER | NAME | LENGTH | WIDTH | .... |
---|---|---|---|---|
2564 | SPOON_1 | 200 | 20 ... | |
2564 | SPOON_2 | 300 | 20 ... | |
2564 | SHOES_1 | 500 | 20 ... | |
2564 | SHOES_2 | 600 | 20 ... |
对象的描述通过 ID_ORDER 和名称链接到项目 table。(不可能有 2 个名称相同的项目,但在同一订单中有不同的描述)。
我发现更快的方法是使用 C#(我比较了所有时间):
我提出请求
SELECT * FROM items WHERE ID_ORDER=2567
,return 是我List<Item>
。然后我按名称分组,以在列表中包含项目名称列表:
List listNames=listItems.Select(x=>"'"+x.Name+"'").Distinct().ToList();
我发出第二个请求,将查找所有对应的描述:
string query = "SELECT * FROM description WHERE ID_ORDER=2567 AND NAME IN ("+string.Join(",",listNames)+")";
即使我的订单中有 1000 件商品,但只有 50 件不同的商品,在第一次查询中我 return 所有 1000 件商品,然后在第二次查询中我 return 只有 50 条描述。
所以最后我只需要做类似的事情:
foreach(Item item in listItems)
{
item.Description=listDescriptions.FirstOrDefault(x=>x.Name==item.Name);
}
现在,我试图在一个 SQL 请求中完成所有工作。这是我现在拥有的:
SELECT * FROM items INNER JOIN description
ON (description.ID_ORDER=items.ID_ORDER AND description.NAME=items.NAME)
WHERE ID_ORDER= 2564
据我了解,问题是 SQL 将搜索项目列表,然后将搜索每个项目的描述,并且看起来更多时间,因为描述是大数据。 有没有更快的方法让 SQL 首先读取与我的项目列表对应的所有描述,然后将描述应用于每个项目?我也试过 RIGHT JOIN(我相信它会那样做),但它花费的时间几乎和简单的 JOIN 一样多,使用 C# 仍然是更快的方法。
您可以使用 EXPLAIN 命令,它会让您知道 MySQL 计划如何回答您的查询。您可以使用它来优化您的查询 运行 更快,或者只是为了了解它是如何工作的。参见 https://dev.mysql.com/doc/refman/8.0/en/explain.html
例如:
EXPLAIN SELECT * FROM items INNER JOIN description
ON (description.ID_ORDER=items.ID_ORDER AND description.NAME=items.NAME)
WHERE ID_ORDER=2564
JOIN
包括根据 ON
匹配的 table 和 行。 (或者关系可能隐藏在不属于它们的 WHERE
中。WHERE
应该仅用于过滤。)
LEFT JOIN
包括“左”table 的所有行和“右”table 的任何匹配行,无论它们是否匹配。不匹配的行在列中显示 NULL
。
FROM a LEFT JOIN b ON ... WHERE b.id IS NULL
是用于查找 a
行的模式,对应的 b
行是 missing`。
RIGHT JOIN
是交换了 table 的 LEFT JOIN
。 (别用这个,我脑袋疼。)
CROSS JOIN
具有两个 table 行的所有组合。相当于WHERE
子句中没有ON
,也没有'relationship'。
“commajoin”是旧语法:FROM a,b WHERE a.foo=b.foo
。不要使用它;如果你这样做,本论坛的回复者会打你的手。
关键字 INNER
和 OUTER
不相关并被 MySQL 忽略 。
FULL OUTER JOIN
是 MySQL 不支持的功能和语法。它可以用 JOIN
和 LEFT JOIN
结合 UNION
.