SQL - 使用共享索引连接多个表
SQL - Joining multiple tables with shared index
我有三个数据 table 不同的列(每列 <500)但共享一个公共“id”列。
它们看起来像:
table一个
id A1 A2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
tableB
id1 B1 B2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
table C
id2 C1 C2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
我的目标是让他们加入类似这样的组织:
id A1 A2 ... B1 B2 ... C1 C2 ...
1 xxx xxx ... xxx xxx ... xxx xxx ...
2 xxx xxx ... xxx xxx ... xxx xxx ...
... ... ... ... ... ... ... ... ... ...
我试图使用
将它们连接在一起
CREATE TABLE my_table
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id1
LEFT OUTER JOIN table_C
ON table_A.id = table_C.id2;
这已经花了好几个小时了。但是使用以下方法加入其中两个只需不到 5 分钟:
CREATE TABLE my_table
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id1
我尝试使用 EXPLAIN
,结果如下:
id select_type table type posibble_keys key key_len ref rows filtered Extra
1 SIMPLE table_A ALL (Null) (Null) (Null) (Null) 59670 100
1 SIMPLE table_B ALL (Null) (Null) (Null) (Null) 39776 100 Using; Using join buffer (Block Nested Loop) where
1 SIMPLE table_C ALL (Null) (Null) (Null) (Null) 50208 100 Using; Using join buffer (Block Nested Loop) where
我四处搜索,发现帖子说“使用连接缓冲区(块嵌套循环)”是一种低效率的方式,并建议使用 SET optimizer_switch='block_nested_loop=off';
禁用它。然而,当我尝试这样做时,即使连接两个 table 也需要 10 多分钟,这似乎是性能的巨大下降。
似乎 BNL 仅在没有索引可加入时才使用,这不是真的,因为所有三个 table 都有“id”列?
我真的很想知道是否有某种方法可以使这些 table 的连接更快。
- 也许我应该调整加入我的代码的方式?
- 也许我应该选择一些选项 on/off?
- 有什么建议吗?
如果较小的连接工作得更快,请尝试按这些较小的步骤进行。
从类似
的内容开始
CREATE temporary TABLE my_table_AB
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id
然后
CREATE TABLE my_table
SELECT *
FROM my_table_AB
LEFT OUTER JOIN table_C
ON my_table_AB.id = table_C.id
另一件事是 - 你需要在这里有 LEFT JOIN
吗?
因为它被标记为已解决并且我们在讨论中找到了解决方案,所以我将它放在这里仅供参考 - 缺少主键的问题。添加后,效果如预期。
您可能正在生成三个表之间的笛卡尔积。您可以使用以下方法计算结果集中的总行数:
select sum(a.cnt * coalesce(b.cnt, 1) * coalesce(c.cnt, 1))
from (select id, count(*) as cnt from a group by id) a left join
(select id, count(*) as cnt from b group by id) b
on a.id = b.id left join
(select id, count(*) as cnt from c group by id) c
on a.id = c.id;
我猜这个数字比你预期的要大得多。这是因为 b
和 c
都有一些 id
的多行。您还没有解释在这种情况下您想要什么结果,因此很难为您的问题提供实际的解决方案。但这应该可以解释性能问题。
它可能令人窒息,因为您正试图从 select 创建 table。问题是新 table 不能与 table 中的列名称重复。您可能需要明确说明,例如
CREATE TABLE my_table
SELECT
a.id,
a.A1,
a.A2,
a.[rest of columns],
b.B1,
b.B2,
b.[rest of columns],
c.C1,
c.C2,
c.[rest of columns]
FROM
table_A a
LEFT JOIN table_B b
ON a.id = a.id
LEFT JOIN table_C c
ON a.id = c.id
对于 500 行,它应该几乎是瞬时的
由于我们需要所有 3 个表中的所有列基于所有表的 id 列的连接,我们不能在这里使用 INNER JOIN 而不是左连接吗?
我有三个数据 table 不同的列(每列 <500)但共享一个公共“id”列。
它们看起来像:
table一个
id A1 A2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
tableB
id1 B1 B2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
table C
id2 C1 C2 ...
1 xxx xxx ...
2 xxx xxx ...
... ... ... ...
我的目标是让他们加入类似这样的组织:
id A1 A2 ... B1 B2 ... C1 C2 ...
1 xxx xxx ... xxx xxx ... xxx xxx ...
2 xxx xxx ... xxx xxx ... xxx xxx ...
... ... ... ... ... ... ... ... ... ...
我试图使用
将它们连接在一起CREATE TABLE my_table
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id1
LEFT OUTER JOIN table_C
ON table_A.id = table_C.id2;
这已经花了好几个小时了。但是使用以下方法加入其中两个只需不到 5 分钟:
CREATE TABLE my_table
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id1
我尝试使用 EXPLAIN
,结果如下:
id select_type table type posibble_keys key key_len ref rows filtered Extra
1 SIMPLE table_A ALL (Null) (Null) (Null) (Null) 59670 100
1 SIMPLE table_B ALL (Null) (Null) (Null) (Null) 39776 100 Using; Using join buffer (Block Nested Loop) where
1 SIMPLE table_C ALL (Null) (Null) (Null) (Null) 50208 100 Using; Using join buffer (Block Nested Loop) where
我四处搜索,发现帖子说“使用连接缓冲区(块嵌套循环)”是一种低效率的方式,并建议使用 SET optimizer_switch='block_nested_loop=off';
禁用它。然而,当我尝试这样做时,即使连接两个 table 也需要 10 多分钟,这似乎是性能的巨大下降。
似乎 BNL 仅在没有索引可加入时才使用,这不是真的,因为所有三个 table 都有“id”列?
我真的很想知道是否有某种方法可以使这些 table 的连接更快。
- 也许我应该调整加入我的代码的方式?
- 也许我应该选择一些选项 on/off?
- 有什么建议吗?
如果较小的连接工作得更快,请尝试按这些较小的步骤进行。
从类似
的内容开始CREATE temporary TABLE my_table_AB
SELECT *
FROM table_A
LEFT OUTER JOIN table_B
ON table_A.id = table_B.id
然后
CREATE TABLE my_table
SELECT *
FROM my_table_AB
LEFT OUTER JOIN table_C
ON my_table_AB.id = table_C.id
另一件事是 - 你需要在这里有 LEFT JOIN
吗?
因为它被标记为已解决并且我们在讨论中找到了解决方案,所以我将它放在这里仅供参考 - 缺少主键的问题。添加后,效果如预期。
您可能正在生成三个表之间的笛卡尔积。您可以使用以下方法计算结果集中的总行数:
select sum(a.cnt * coalesce(b.cnt, 1) * coalesce(c.cnt, 1))
from (select id, count(*) as cnt from a group by id) a left join
(select id, count(*) as cnt from b group by id) b
on a.id = b.id left join
(select id, count(*) as cnt from c group by id) c
on a.id = c.id;
我猜这个数字比你预期的要大得多。这是因为 b
和 c
都有一些 id
的多行。您还没有解释在这种情况下您想要什么结果,因此很难为您的问题提供实际的解决方案。但这应该可以解释性能问题。
它可能令人窒息,因为您正试图从 select 创建 table。问题是新 table 不能与 table 中的列名称重复。您可能需要明确说明,例如
CREATE TABLE my_table
SELECT
a.id,
a.A1,
a.A2,
a.[rest of columns],
b.B1,
b.B2,
b.[rest of columns],
c.C1,
c.C2,
c.[rest of columns]
FROM
table_A a
LEFT JOIN table_B b
ON a.id = a.id
LEFT JOIN table_C c
ON a.id = c.id
对于 500 行,它应该几乎是瞬时的
由于我们需要所有 3 个表中的所有列基于所有表的 id 列的连接,我们不能在这里使用 INNER JOIN 而不是左连接吗?