【问题标题】:What to replace left join in a view so i can have an indexed view?什么可以替换视图中的左连接,以便我可以拥有索引视图?
【发布时间】:2011-09-22 13:06:06
【问题描述】:

我已经对数据库中的表进行了规范化,为了对其进行非规范化,我从两个表中创建了一个视图。当我尝试在视图上创建聚集索引时,它不会让我这样做,因为视图是使用左外连接创建的。我使用了左连接,因为我希望 null 值显示在结果视图中,就像之前这篇文章中建议的那样。

Question on join where one column one side is null

表结构和关系与上面链接中描述的非常相似。

我似乎在这里碰壁了,因为我无法将左连接转换为内连接,因为这会排除任何连接列上具有空值的所有记录。我的问题是:

  1. 为什么不允许在外连接或自连接上建立索引?
  2. 这种未编入索引的视图是否会影响性能?
  3. 有人知道这个问题的解决方法吗?

我昨天刚刚完成了 SQL Server 课程,所以不知道如何继续。将不胜感激任何cmets。干杯。

【问题讨论】:

  • 您需要 OUTER 表中的列吗?
  • 如果你真的需要索引视图,你可以创建(索引)INNER JOIN 一个。然后,您可以将原始(左侧)表 LEFT JOIN 加入此视图,以获得所需的输出,但具有索引视图的性能增益。
  • @gbn & @ypercube:是的,我需要左侧外部表中的列,不幸的是,这就是我需要唯一聚集索引的地方。

标签: sql sql-server view indexed


【解决方案1】:

这是另一种选择。你想要一个不包含 B 的 A 的物化视图。这不是直接可用的......所以相反,物化两个视图。所有 A 之一和仅有 A 和 B 之一。然后,通过取除 B 之外的 A,只得到 A 没有 B。这可以有效地完成:

创建两个物化视图(mA 和 mAB)(编辑:mA 可能只是基表)。 mA 缺少 A 和 B 之间的连接(因此包含所有 A 的句点 [因此包含那些在 B 中没有匹配项的记录])。 mAB 在 A 和 B 之间连接(因此只包含 A 和 B [因此排除了 B 中没有匹配项的那些记录])。

要在 B 中获取所有没有匹配的 A,请将匹配的那些屏蔽掉:

with ids as (
  select matchId from mA with (index (pk_matchid), noexpand)
  except
  select matchId from mAB with (index (pk_matchid), noexpand)
)
select * from mA a join ids b on a.matchId = b.matchId;

这应该会针对您的聚集索引产生一个左反半连接以获取 ids 和一个聚集索引寻求从您正在寻找的 mA 中获取数据。

基本上,您遇到的基本规则是,SQL 在处理存在的数据方面比处理不存在的数据要好得多。通过实现两个来源,您可以获得一些引人注目的基于集合的选项。您必须自己权衡这些观点的成本与这些收益。

【讨论】:

    【解决方案2】:

    有一个“解决方法”here 涉及在连接中检查 NULL 并在表中具有 NULL 表示值

    空值

    INSERT INTO Father (Father_id, Father_name) values(-255,'No father')
    

    加入

    JOIN [dbo].[son] s on isnull(s.father_id, -255) = f.father_id
    

    【讨论】:

    • @Damien, @gbn:只有我觉得这种“解决方法”看起来很糟糕吗?其他具有SELECT COUNT(*) FROM rightTable 的查询会发生什么情况?您必须更改它们以纠正他们在解决方法后给出的错误(1)?
    • @ypercube 你的权利,这很糟糕而且不是真正的解决方法。但这是实现你想要的唯一方法。更好的解决方案可能是索引基础表并跳过索引视图。
    • @Damien,俗话说:乞丐不能挑剔
    【解决方案3】:

    我认为没有好的解决方法。您可以做的是从视图创建一个真实的表并在其上设置索引。这可以通过在数据更新时定期调用的存储过程来完成。

    Select * 
    into <REAL_TABLE>
    From <VIEW>
    
    create CLUSTERED index <INDEX_THE_FIELD> on <REAL_TABLE>(<THE_FIELD>)
    

    但这只是一个值得注意的方法,如果数据不是每隔几秒更新一次。

    【讨论】:

    • 这是一个很好的解决方案。无需每次都更新整个表。我们可以编写触发器并仅更新更改的行。
    • 尽管我不喜欢手动表更新..东西很容易“丢失”..这在某些情况下是可行的。
    • 批处理操作的问题,性能会很慢。记录更新删除也需要注意,增加更多维护。
    【解决方案4】:

    从逻辑上讲,您正在进行两个单独的查询。 'A LEFT JOIN B' 只是 '(A JOIN B) UNION A' 的简写

    第一个查询是表 A 内部连接到表 B。这将获得一个索引视图,因为这是完成所有繁重工作的地方。

    第二个查询只是表 A,其中任何连接列都为空。创建一个生成与第一个查询相同的输出列并用空值填充它们的视图。

    在返回它们之前将两个结果合并。无需解决方法。

    【讨论】:

    • 这仍然不起作用,因为在使用关键字 UNION、INTERSECT 或 EXCEPT 的视图中不允许使用 INDEX
    • 在宣布它不起作用之前尝试一下。 UNION 的视图可以使用底层视图的索引。
    • 我刚试过,不可能有一个使用 UNION 的索引视图。在这里查看msdn.microsoft.com/en-us/library/ms191432.aspx#Restrictions
    • 为 A JOIN B 创建索引视图 C,然后为 C 联合 A 使用普通视图。
    【解决方案5】:

    我会回答 1,但现在:

    [2]。该视图的性能不会高于或低于对 udnerlying 表的等效查询。所有常见的建议都适用于覆盖索引,最好是连接列上的索引等。

    [3]。没有真正的解决方法。一旦您深入研究它们,大多数索引视图的限制都是有充分理由存在的。

    一般来说,我只是创建视图,不再做任何事情,除非存在特定的性能问题。

    一旦我在自己的脑海中重构了 1,我会尝试添加它的答案。

    【讨论】:

    • MS 程序员懒惰为a LEFT JOIN b LEFT JOIN ... LEFT JOIN z 构建索引视图?
    • @ypercube - 存在大多数限制是因为它们允许维护索引视图而不必对一个或多个基表执行全表扫描(例如,为什么允许的唯一聚合是 SUM,然后仅当还包括 COUNT_BIG 时),或执行其他昂贵的操作。
    • 感谢您回答我的其他问题。干杯。
    • 除了 LEFT JOIN(至少有一些连接条件限制)不需要比 INNER JOIN 更多的索引扫描。不支持这种基本的 LEFT JOIN 场景会使索引视图成为扩展模式的垃圾:所以在这种情况下,它是一个特性/功能缺陷。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 2011-01-23
    相关资源
    最近更新 更多