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 的连接更快。

  1. 也许我应该调整加入我的代码的方式?
  2. 也许我应该选择一些选项 on/off?
  3. 有什么建议吗?

如果较小的连接工作得更快,请尝试按这些较小的步骤进行。

从类似

的内容开始
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;

我猜这个数字比你预期的要大得多。这是因为 bc 都有一些 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 而不是左连接吗?