【问题标题】:SQL join query where foreign key has non of these fields外键不包含这些字段的 SQL 连接查询
【发布时间】:2017-07-23 11:03:43
【问题描述】:

我创建了两个表,如下所示:

create table table1(
    id number(10) not null,
    constraint table1_pk primary key (id)
);

create table table2(
    table1_id number(10) not null,
    x number(10) not null,
    constraint table1_fk foreign key (table1_id) references table1(id)
);

接下来,我将一些随机数据插入到这两个表中。 table1 包含从 1 到 1000 的所有 ID,table2 在 table1_id 字段中包含来自 table1 的 id,在 x 字段中包含 0 到 2 之间的随机数。每个 table1_id 可以有多行,但每个 x 值只能有一次。因此 table2 看起来像这样:

TABLE1_ID   X
    1       0
    1       1
    2       0
    2       2
    3       0
    4       2
    5       0
    6       2
    7       2
    8       0
    8       1

我想从 table1 中选择所有行,其中 table2 中的匹配 table1_id 在 x 列中既没有 1s 也没有 2s(对于上面的示例,结果应该只包含 id 3 和 id 5)。但是,如果我将数字 3 添加到 x 的可能选项中,则正确的结果将包括所有具有 0 或 3 且不具有 1 或 2 的字段。

下面的查询做了我想要的,但不幸的是它太慢了:

select * from table1 where id not in (select t1.id from table1 t1 join table2 t2 on t1.id = t2.table1_id where t2.x = 1 or t2.x = 2);

无论如何,我都不是 SQL 专家,但我很确定有一种更快的方法可以做到这一点,可能是通过不同的连接或添加索引(我尝试过,但没有帮助)。也许更专业的人可以帮助我找到解决方案。

提前致谢!

编辑:由于我现在尝试了一些查询,并且所有查询都花费了大约相同的时间(0.8 秒),我还有另一个问题:table1 有 1000 行,table2 有 1569 行。 0.8s真的合理吗?

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    我认为性能问题主要是由于表结构。如果我要这样做,我会像这样合并两个表:

    create table table1(
        id number(10) not null,
        hasValue0 bit,
        hasValue1 bit,
        hasValue2 bit,
        constraint table1_pk primary key (id)
    );
    

    所以现在,每当您向 table2 插入新条目 (3, 1) 时,您都应该像这样运行更新查询:

    update table1  set hasValue1 = 1 where id = 3
    

    我希望你能明白。与您当前的设计相比,这种结构的优势在于:

    • 它需要更少的磁盘空间,因为与之前的 3 个数字字段相比,现在您有 3 个位字段和 1 个数字字段。

    • 您不必拥有两个表之间的外键或索引,这也略微节省了磁盘空间。

    • 最重要的是,您需要的查询非常高效:

      select * from table1 where hasValue1 is null and hasValue2 is null
      

    也许您应该尝试一下,看看您是否发现任何性能优势。

    注意:我使用的是 MS SQL Server,所以如果有任何语法错误请见谅,或者如果有什么不清楚的地方请告诉我。

    【讨论】:

    • 感谢您的回复,但我不能采用此解决方案,因为该项目仅代表我的实际问题,其中 'x' 的值可能比 0、1 更多和 2。例如,如果我想添加 3 和 4 作为可能的值,我必须再添加两列。现在想象一下,我想提高到 100。所以,不幸的是,这不是一个潜在的解决方案。
    • 公正的批评。而且,我没有意识到您可能想要达到 100。但我会说在表中有 100 位字段是可以的!除非你可能打算超越这个。我承认,我曾经讨厌列太多的表格,但我了解到它们有时很有用。因此,如果您不喜欢这个想法,@GordonLinoff 的解决方案应该是更好的 IMO。拥有一个索引会给你一些你需要的性能提升。要尝试的另一件事可能是在子查询末尾用t2.x in (1,2) 替换t2.x = 1 or t2.x = 2
    • 我认为更大的问题是我不知道可能会出现哪些字段。例如,如果您理解我的意思,我可能需要 352,但不需要 175,并且 x 可以采用哪些值的决定不在我的权力范围内。对不起,我说的很神秘,但我不想进入领域知识。我添加了一个索引(甚至将字段的组合做成了一个 PK),并切换到 (1,2) 中,但没有得到太多的性能提升。
    • 也许您可以通过具有领域知识的人找出您需要多少不同的值。如果这个范围很小,我相信我的建议会更好。但是,如果您有一个非常大的数字,您就有可能达到表中允许的最大列数的限制。
    【解决方案2】:

    我会用not exists写这个:

    select t1.*
    from table1 t1
    where not exists (select 1
                      from table2 t2
                      where t2.table1_id = t1.id and
                            t2.x in (1, 2)
                     );
    

    然后为了性能,您需要在table2(table1_id, x) 上建立索引。

    【讨论】:

    • 你忘记了table2后面的t2。否则查询会做它应该做的,虽然比原来的慢。
    【解决方案3】:

    也许使用外连接会更快:

    select table1.*
    from table1 left join (select table1_id
                           from table2
                           where x = 1 or x = 2) t2 on (table1.id = t2.table1_id)
    where t2.table1_id is null;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多