SQL JOIN有两个或多个表作为输出 - 最有效的方法?

时间:2010-05-06 08:17:28

标签: sql sql-server tsql

我有一个SQL查询在另一个表上执行LEFT JOIN,然后输出可以耦合到指定表中的所有结果。然后我有第二个SQL查询再次执行LEFT JOIN,然后输出无法耦合到指定表的结果。在代码中,这类似于:

INSERT INTO coupledrecords
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
LEFT JOIN smallertable AS s
ON criterium
WHERE s.col1 IS NOT NULL

INSERT INTO notcoupledrecords
SELECT b.col1, b.col2... bigtable AS b
LEFT JOIN smallertable AS s
ON criterium
WHERE s.col1 IS NULL

我的问题:我现在必须执行两次JOIN,以达到我想要的效果。我觉得这是它的两倍慢。这是真的,如果是的话,有没有办法更有效地做到这一点?

5 个答案:

答案 0 :(得分:4)

如果您将不同的结果插入2个不同的表中,则需要2个不同的查询。

我唯一建议的是,“coupledrecords”查询可以只是一个INNER JOIN:

INSERT INTO coupledrecords
SELECT b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
INNER JOIN smallertable AS s 
ON criterium

如果您要插入SAME表,并带有一个字段来指示它是否是匹配的记录,那么您可以将其作为一个查询进行。

答案 1 :(得分:3)

底线是,您需要2个查询,因为您要插入2个不同的表。如果你只有一个表而不是coupledrecords和notcoupledrecords,那么你可以在1个查询中完成。 :)

答案 2 :(得分:3)

我认为你能做到的一种方法是创建一个分区视图,在列上指示耦合/未耦合的检查约束。然后插入视图,让SQL Server找出目标表。并没有暗示你这样做只是因为我认为它是一种可能性!

INSERT INTO coupledrecordsView
SELECT case WHEN s.col1 IS NULL THEN 1 ELSE 0 END AS IsCoupled,
b.col1, b.col2... s.col1, s.col2... FROM bigtable AS b
LEFT JOIN smallertable AS s
ON criterium

答案 3 :(得分:2)

如果您可以更改coupledrecordsnotcoupledrecords的聚簇索引以包含smalltable中的一列(包括在每个聚簇索引的末尾添加计算位列,仅用于此目的 - 请参阅@Martin Smith上面的答案详细说明)然后你可以使用Partitioned View作为插入。这很容易。

如果不可能,那么您也可以尝试非分区视图解决方案。见下文 - 它涉及更多。

在不知道数据如何分布的情况下(例如行大小,可空列与不可空列的数量,耦合与非耦合的比率),很难推荐一般解决方案,但在大多数情况下可能运行良好的一种解决方案是使用视图在单个“maybecoupled”表格上模拟耦合和非耦合表。使用视图意味着您不必更改现有的查询代码(插入除外)。

乍一看这看起来非常低效,但请记住空值占用零存储空间,并且使用适当的索引,SQL不会浪费太多过滤掉“其他视图”行。

以下是它的工作原理:

  • 一次性将所有记录插入基表(例如maybecoupled
  • 确保从smalltable获得的一个列上有一个索引(理想情况下是聚簇索引,但非聚簇也可以)。我们假设这是indexedcol1
  • 在顶部创建两个视图:coupledrecordsnotcoupledrecords,其定义为SELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NULLSELECT col1, ... FROM maybecoupled WHERE indexedcol1 IS NOT NULL
  • 如果你在indexedcol1上有一个聚集索引,那么你将为大多数查询支付很少或没有支付惩罚,因为对任一视图的每个查询只会达到相应的一半记录而从不接触另一半。你的非聚集索引会变得更大,因此会慢一点,但即便如此,filtered indexes也可以改善。
  • 如果您不能使用聚簇索引,请确保indexcol1是每个非聚集索引的一部分(或INCLUDE-d)。这样可以防止必须返回聚簇索引以查找仅从非聚集索引中提取数据的查询的indexcol1。

以下解决方案无效的情况如下:

  • 如果耦合行的数量相对较小,并且您在bigtable中有很多不可为空的列,或者您的行数非常少。那么所有那些非耦合行的空间开销可能会受到伤害。 (nulls不占用空间,但不可为空的列。)
  • 如果您使用的是非聚集索引col1并且无法更改索引以确保indexcol1存在于非聚簇索引中
  • 如果上面的恶作剧导致SQL Server选择错误的索引在查询计划中使用,因为查询的复杂性增加(尽管您可以使用索引提示修复此问题)

警告:你肯定想测试任何基于视图的解决方案的性能,以确保它不会让事情变得更糟 - SQL通常擅长选择好的查询计划,但并非总是如此。测试,测试,测试!

答案 4 :(得分:0)

你基本上将数据改为两个。一旦你完成了它,一旦你有一组关键记录,你应该只从那里做 NOT IN

INSERT INTO notcoupledrecords
SELECT b.col1, b.col2... bigtable AS b
WHERE some_col not in (select some_col from coupledrecords)