比较 SQL Server 2008 中的 DISTINCT、GROUP BY 和 ROW_NUMBER() 与数据仓库工作负载

Ste*_*eld 5 sql-server query

我最近听到了这样的建议:“如果您使用的是 DISTINCT,我会挑战您修复您的代码。” 但是,我想知道这个建议背后的考虑因素,以及这是否意味着我应该以不同的方式处理以下问题。

问题背景

我有一个非规范化的日期维度表(Kimball 星型架构)。在这张表中,我折叠了几个第三范式表:日期、绝对周、绝对月和年。对于这些折叠表中的每一个,我都有一个表示唯一标识的列、一个文本名称列和一个数字手动排序索引。这是显示结构的示例行,数字仅用于说明(为便于阅读采用垂直形式):

  • 日期编号:20110507
  • 日期名称:2011 年 5 月 7 日
  • 日期订单:17813
  • 周号:201118
  • :2011 年第 18 周
  • 周订单:617
  • 月号:201105
  • MONTHNAME:2011年5月
  • 月订单: 74
  • 年份编号:2011
  • 年份名称: 2011
  • 年订单: 41

为了便于理解,我选择使用日期维度表,但该问题可以转换为任何其他涉及层次结构的维度表。

问题概要

我想用相关的文本字段检索一组不同的周和月组合。

可能的解决方案

1. 与众不同

SELECT DISTINCT MonthId, WeekId, YearName, MonthName, WeekName
  FROM DimDate
Run Code Online (Sandbox Code Playgroud)

请注意,我不能排除 MonthId 或 WeekId,因为我不能假设自由文本字段是唯一的。

2. 分组依据

SELECT MIN(YearName), MIN(MonthName), MIN(WeekName)
  FROM DimDate
 GROUP BY MonthId, WeekId
Run Code Online (Sandbox Code Playgroud)

3. 行号

WITH grp AS (
  SELECT YearName, MonthName, WeekName
       , ROW_NUMBER() OVER (PARTITION BY MonthId, WeekId) AS r
    FROM DimDate
)
SELECT YearName, MonthName, WeekName
  FROM grp
 WHERE grp.r = 1
Run Code Online (Sandbox Code Playgroud)

4.ETL

在这种方法中,非叶属性的每个组合的索引视图都被预先计算并直接查询。显然,这在查询时是最快的,但可能需要多次复制维度表,具体取决于维度中层次结构的复杂性。

注释

我希望该ROW_NUMBER解决方案是最快的(不包括ETL方法),但它还需要查询规范中的子查询或 CTE。虽然这不是一个严重的问题,但它确实使查询更难阅读。我希望GROUP BYDISTINCT方法几乎是等效的,因为每个列都必须以某种形式的排序操作使用,而ROW_NUMBER解决方案只需要对分区列进行排序。

我错过了什么吗?SQL Server 能否更有效地使用非规范化列标识的非唯一索引?

--edit - 附加说明:

  1. 周和月标识符是绝对的,因此在此方案中它们表示年份。我强制要求周仅在一年中。在 SSAS 中,将有两个层次结构:日期、周、年和日期、月、年。

  2. 我相信 DISTINCT 给出了相同的输出,因为请求的列仅因周、月或年而异,而周和月都暗示了年。

  3. 索引目前仅在标识符列上(单列非唯一)

通常,我正在对事实表执行聚合查询,但通过一组由最终用户选择且事先未知的非叶维度属性进行报告。我试图减少这个问题的问题空间。

gbn*_*gbn 3

根据我的经验,聚合(DISTINCT 或 GROUP BY)可能比 ROW_NUMBER() 方法更快。也就是说,SQL Server 2008 的 ROW_NUMBER 比 SQL Server 2005 更好。

不过,你还是得根据自己的情况去尝试一下。
比较查询计划,并使用Profiler和SET捕获IO、CPU、Duration等

有关大量背景信息,请参阅以下问题:

最后,您是否需要 ROW_NUMBER 方法?看起来您正在解决由非规范化引起的问题。

还有一些注意事项:

  • YearID 不应该在 GROUP BY 或 PARTITION BY 中吗?
  • DISTINCT 不会给出不同的输出吗?
  • 这些列是否已建立索引?