【问题标题】:How to convert rows to columns in indexed view?如何在索引视图中将行转换为列?
【发布时间】:2012-03-19 00:58:37
【问题描述】:

我使用 OUTER JOIN 来获取存储在行中的值并将它们显示为列。当没有值时,我在列中显示 NULL。

源表:

Id|Name|Value
01|ABCG|,,,,,
01|ZXCB|.....
02|GHJK|;;;;;

查看:

Id|ABCG|ZXCB|GHJK
01|,,,,|....|NULL
02|NULL|NULL|;;;;

查询看起来像:

SELECT DISTINCT
    b.Id,
    bABCG.Value AS "ABCG"
    bZXCB.Value AS "ZXCB"
    bGHJK.Value AS "GHJK"
FROM
    Bars b
    LEFT JOIN Bars bABCG ON b.Id = bABCG.Id and b.Name = 'ABCG'
    LEFT JOIN Bars bZXCB ON b.Id = bZXCB.Id and b.Name = 'ZXCB'
    LEFT JOIN Bars bGHJK ON b.Id = bGHJK.Id and b.Name = 'GHJK'

我想删除 LEFT JOIN,因为它在索引视图中是不允许的。我尝试用内部 SELECT 替换它,但内部 SELECT 也不允许,UNION 也不允许。我不能使用 INNER JOIN 因为我想在视图中显示 NULL。我应该使用什么?

【问题讨论】:

  • 你试过用FROM bars b,bars b1,bars b2 where (b.id=b2.id and b.name='asdfa') and (b.id=b2.id and b.name='sdaf') ....
  • 是的,但这不会返回空值。
  • 提示:如果您遇到了一个限制,在索引视图中不允许使用特定方法,那么您尝试的任何其他形式(产生相同的结果集)也将不允许。您将无法使用您所描述的形状生成索引视图。
  • 另外,即使有针对连接问题的解决方法(正如我所说,我怀疑没有),也不允许在索引视图中使用DISTINCT
  • DISTINCT可以去掉,没问题。感谢您注意到这一点。

标签: sql sql-server views left-join indexing


【解决方案1】:

也许可以使用一个实际的表来存储结果,并使用一组针对基表的触发器来维护内部数据。

相信,当您创建索引视图时,这就是 SQL Server 所做的(在精神上,如果不是在实际实现中)。但是,通过检查索引视图的规则,很明显触发器应该使用inserteddeleted 表,并且不应该被要求扫描基表来执行维护 -否则,对于大型表,维护此索引视图会带来严重性能损失。

作为上述示例,虽然您可以轻松编写插入触发器以在视图中维护 MAX(column) 列,但删除会更成问题 - 如果您要删除当前最大值,则需要扫描表以确定新的最大值。对于许多其他限制,请尝试手动编写触发器,大多数情况下,您需要扫描基表。

现在,在您的特定情况下,我相信这些触发器执行维护可能相当有效 - 但您需要仔细考虑所有插入/更新/删除场景,并确保您的触发器实际上忠实地维护这些数据 - 例如如果您更新任何ids,您可能需要混合执行更新、插入和删除操作。

【讨论】:

    【解决方案2】:

    您能做的最好的事情是使用内连接来获取匹配项,然后与左连接联合并过滤它以仅返回空值。这可能无法解决您的问题。

    我不知道您的系统的具体情况,但我假设您正在处理性能问题,这就是您想要使用索引视图的原因。有几种选择,但我认为以下是最合适的。

    既然您评论这是针对 DW,我将假设您的系统在读取方面比写入更加密集,并且数据通过 ETL 进程按计划加载到其中。在这种高读/低写*的情况下,我建议您“实现”此视图,这意味着当 ETL 流程运行时,使用包含左连接的初始选择语句生成表。您将受到写入的影响,然后您的所有读取都将与索引视图的性能相提并论(您将做与索引视图相同的事情,除了批量而不是逐行)。如果您的源数据库和 DW 在同一个实例上,这是比索引视图 b/c 更好的选择,它不会影响源系统的性能(索引视图会减慢插入速度)。这与索引视图的概念相同,因为您在插入时会降低性能以加快选择速度。

    我以前一直在这条路上走,得出以下结论:

    索引视图更可能是解决方案的一部分,而不是整个解决方案。

    *当我上面说“高读/低写”时,您也可以将其视为“高读/预定写”

    【讨论】:

    • 抱歉,我的评论不准确。我的系统是 DW 的数据来源。该索引视图旨在作为 DW 查找预先计算数据的单一位置。 DW 将每隔 5 小时从我的系统加载数据。我无法更改 DW。
    • 在考虑了你的 PoV 之后,我想我只是把它作为没有索引的常规视图......
    • 我认为让 ETL 每 5 小时承受一次性能冲击而不是您的源系统在每次插入时承受一次性能冲击是有意义的。在这里使用常规视图似乎很合适。
    【解决方案3】:
    SELECT DISTINCT
        b.Id,
        (Select bABCG.Value from Bars bABCG where b.Name = 'ABCG')  AS "ABCG"
        ...
    FROM
        Bars b
    

    您可能需要对值添加聚合,我不确定您的数据是如何组织的

    【讨论】:

    • 这是我的第一次尝试。但是正如我在问题中所写的那样,为了在 MSSQL 中创建索引视图,不允许内部 SELECT(子查询)(“无法在视图上创建索引,因为它包含一个或多个子查询。考虑将视图更改为仅使用连接而不是子查询。或者,考虑不为此视图编制索引。”)。
    • 我不认为你可以!除非您使用某种左连接,否则永远不会显示“NULL”。关于另一个话题,请问为什么需要索引视图?您知道这样做时会将视图的数据保存在数据库中吗?您基本上已经拥有数据的副本?
    • 这是数据仓库场景,所以我认为使用索引视图是合理的。
    • 这取决于几个因素,但由于索引视图会创建大量数据,这可能是最糟糕的
    • 是的,但我真的很想制作这个索引视图。也许我应该使用 CASE 或 PIVOT?我没有这方面的经验。
    猜你喜欢
    • 1970-01-01
    • 2021-12-17
    • 2014-02-04
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多