3

我希望优化以下 SQL 语句,该语句从历史表中创建透视结果集。这可能已经是最高效的方式了,但我一直认为必须有一种更高效的方式来做到这一点。

我正在尝试优化的 SQL 语句

select Col1, Col2,
Max(case when TypeId = 1 then ColValue end) as Pivot1,
Max(case when TypeId = 2 then ColValue end) as Pivot2,
Max(case when TypeId = 3 then ColValue end) as Pivot3,
Max(case when TypeId = 4 then ColValue end) as Pivot4,
Max(case when TypeId = 5 then ColValue end) as Pivot5,
Max(case when TypeId = 6 then ColValue end) as Pivot6,
Max(case when TypeId = 7 then ColValue end) as Pivot7,
Max(case when TypeId = 8 then ColValue end) as Pivot8,
Max(case when TypeId = 9 then ColValue end) as Pivot9,
Max(case when TypeId = 10 then ColValue end) as Pivot10,
Max(case when TypeId = 11 then ColValue end) as Pivot11
from RowTable
group by Col1, Col2

更新:下面是表定义

CREATE TABLE dbo.RowTable  ( 
    Id                  int NOT NULL,
    Col1                char(8) NOT NULL,
    Col2                tinyint NOT NULL,
    TypeId              int NOT NULL,
    ColValue            datetime NOT NULL,
    CreatedBy           varchar(50) NOT NULL,
    Rowstamp            timestamp NOT NULL 
    )
LOCK DATAROWS
GO
ALTER TABLE dbo.RowTable
    ADD CONSTRAINT ukRowTable
    UNIQUE (Col1, Col2, TypeId)
    WITH max_rows_per_page = 0, reservepagegap = 0
4

2 回答 2

1

对原始问题的回应

1. 表原样的性能。
好吧,在任何人都可以评估该代码之前,我们需要创建表语句,包括索引。

  1. 更高级别的性能。
    透视是一种以行、列表示可用数据的功能。如果说数据库(表)被规范化为面向行的 3NF 或 5NF,那么对行对象执行列函数会很慢。与产品无关。如果您想要快速进行列访问(对于 Pivoting 或任何其他列功能),您需要 6NF 中的数据。这也恰好使任务所需的 SQL 更加直接。

    如果您的数据建模师准备了用于透视的表(通常是数据仓库类型使用;Dimension-Fact 结构),那么它可能不是真正的 6NF,但至少它会比 5NF 更好,并且更容易提取 Pivoted 值。当我看到 DDL 时,我将能够确定它是什么(真正的 6NF;优于 5NF 但不是 6NF)。然后我可以确定您是否使用最佳代码来获得所需的内容。

    当表不在 6NF 中时,它只会很慢或“昂贵”。

  2. 在这个阶段,从您的代码来看,它甚至看起来不像一个 Pivot(使用该术语的标准含义),它看起来像一个MAX()具有各种值的(调用结果列Pivotx不会使其成为 Pivot);你正在阅读每一行,一次。也就是说,你有一个程序性的心态,而不是一个枢轴或面向集合的心态。因此,代码很可能无法获得您需要的值(无论它是否执行良好,是一个单独的问题)。

    您的使用GROUP BY确认了非程序集的程序方法,这会很慢(创建工作表;如果您的数据很大,这将是巨大的),并且可以通过维度更快地获得相同的信息。你为什么不使用这个可透视表的维度表?发布与此表相关的所有维度表的 DDL,或发布数据模型。

回应评论

我想帮助你,但有两个障碍。首先,互动间隔为 19 天。其次,您发布的 SQL 将不起作用:对于每一行,它ColValue在 11 列中返回相同的;我无法弄清楚您使用MAX(). 好的,MAX()需要击败GROUP BY提交。因此,我仍然不知道您的意图是什么(而不是您编码的内容)。混淆是公平的,但在这里我们失去了意义。

是的,有更快的方法,但我需要了解意图和父表(例如,你有一个(Col1, Col2)唯一的表吗?如果它是一个数据库,那么表不是独立的,它们是相关的,并且关系有一些目的。我知道您认为它们不相关,但是该限制产生了您发布的代码;解决方案超出了该限制。

无论如何,为了避免进一步的延迟,请尝试此代码。这只是一个猜测,对我来说似乎不正确,因为(Col1, Col2, TypeId)是唯一的;因此TypeId,每个结果行将只有一组(结果集中的列标题)Col1, Col2

[Superceded, refer below]

也许你可以给我反馈。

对更新问题的回应

好的,现在我们有一个非规范化的表。新的步骤集。它是一个构造的结果集,使用返回标量的相关子查询。这不是行与列的重新排列;它不是标准枢轴(因此提供的代码不是枢轴)。容易死。您可能希望更改问题标题,因为人们正在寻找真正的 Pivot。是的,这将执行得更好(假设您的 DDL 是真实表的真实表示)。

需要明确的是,Pivot(ala MS SQLPIVOT函数)是另一种动物。我可以为非规范化数据库提供一个丑陋而缓慢的 Pivot;或来自 5NF 数据库的干净但缓慢的 Pivot;或来自 6NF 数据库的干净快速的 Pivot。这不是它。

  1. 假设它是一个关系数据库。鉴于提供的 DDL,将有一个(Col1, Col2)唯一的 ParentTable。

  2. 编码:

    SELECT  Col1, 
        Col2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 1 ) as Latest_1,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 2 ) as Latest_2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 3 ) as Latest_3,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 4 ) as Latest_4,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 5 ) as Latest_5,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 6 ) as Latest_6,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 7 ) as Latest_7,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 8 ) as Latest_8,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 9 ) as Latest_9,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=10 ) as Latest_10,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=11 ) as Latest_11
    FROM ParentTable  OUTER

  3. 如果没有 ParentTable(即它不是关系数据库),请使用 动态创建一个SELECT-INTO,或使用派生表:

    SELECT  Col1, 
        Col2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 1 ) as Latest_1,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 2 ) as Latest_2,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 3 ) as Latest_3,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 4 ) as Latest_4,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 5 ) as Latest_5,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 6 ) as Latest_6,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 7 ) as Latest_7,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 8 ) as Latest_8,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId= 9 ) as Latest_9,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=10 ) as Latest_10,
        ( SELECT ColValue FROM RowTable WHERE Col1=OUTER.Col1 AND Col2=OUTER.Col AND TypeId=11 ) as Latest_11
    FROM (
        SELECT DISTINCT
                Col1,
                Col2
            FROM RowTable
        )  OUTER

  4. 你可以去掉IdRowTable 中的列,它是一个 100% 冗余的列和索引,没有任何用处。

于 2010-11-28T00:47:41.523 回答
0

旋转是一种固有的昂贵操作。我不认为这可以优化。

于 2010-11-26T13:16:15.960 回答