Tabular Editor 技巧 – 转换为旧版 Legacy

此内容由人工智能翻译,尚未经过人工编辑审核。图像和图表保持其原始语言。
重要提示

本文中的信息专门针对将语义模型部署到 SQL Server Analysis Services(SSAS)或 Azure Analysis Services(AAS)时使用的 Tabular Editor 2。在使用 Power BI / Fabric 时,我们不建议使用旧版(提供程序)数据源。

 

将分区从 M 转换为旧版

在基于关系数据库的数据仓库或数据集市之上构建 Analysis Services 表格模型时,我建议使用旧版 (Provider) 数据源,而不是自 SQL Server 2017 起提供的 Power Query 数据源。 遗憾的是,Power Query 数据源已经成为 SSDT 的默认选项,而且 创建旧版数据源也变得相当棘手(简而言之:在“选项”>“Analysis Services 表格”>“数据导入”中勾选“启用旧版数据源”)。

我之所以更偏好旧版数据源,主要有以下几个原因:

  • 刷新性能相近,但根据我的经验,Power Query 数据源在初始化时会有少量额外开销。如果你需要频繁进行许多小规模刷新,这可能会比较令人头疼。
  • 无论如何,你都不希望在表格模型的分区查询中做任何 M 转换——这正是引入 ETL 流程的意义:将数据加载到关系数据源上的星型架构中。
  • 部署模型或执行 CreateOrReplace TMSL 脚本时,旧版数据源使用的凭据不会被清除。
  • 你可以使用非常好用的 Tabular Editor 导入表向导

如果你已经使用 Power Query 数据源和 M 分区创建了模型,下面是切换到旧版所需的步骤:

  1. 在模型中创建一个旧版数据源,并将其指向你的关系数据库。 给它起个名字,例如“SQLDW”。
  2. 将以下脚本粘贴到 Tabular Editor 的“高级脚本”选项卡中: var legacy = (Model.DataSources["SQLDW"] as ProviderDataSource); foreach(var table in Model.Tables) { if(table is CalculatedTable || table is CalculationGroupTable) continue; table.Partitions.ConvertToLegacy(legacy); // foreach(var partition in table.Partitions) partition.Query = "SELECT * FROM " + table.Name; }
  3. 在运行脚本之前,如果你给新的旧版数据源起了不同的名称,请在第 1 行相应调整数据源名称。
  4. (可选) 如果模型中导入的表名与数据源中的表或视图名称一致,你可以取消第 7 行的注释,从而自动将每个分区的查询设置为基本的 SELECT * FROM <表/视图名> 查询。
  5. 运行脚本
  6. 逐个检查模型中的每个分区,确认分区类型正确 (旧版),并且分区使用了正确的数据源。 如果你跳过了第 4 步,也请确保在每个分区中输入正确的 SQL 查询:SQL query on partition
  7. 删除 Power Query 数据源。此时它应该已经不再被模型中的任何分区使用。

就是这样——模型中的所有分区现在都已 100% 转为旧版分区。

补充说明

2020 年八月更新:如果你取消第 7 行的注释,原脚本存在一个 bug:循环会遍历模型中的 ALL 表,包括计算表格和计算组表格。 把计算表格的 DAX 表达式设为“SELECT * FROM …”多半不是你想要的;如果模型里包含计算组表格,脚本甚至会直接崩溃。 这是因为计算组表格上的分区不支持 Query 属性。 我在第 5 行增加了检查,用来跳过模型中的所有计算表格或计算组表格。

脚本调用的 Partitions.ConvertToLegacy(<data source>) 方法会将表格上的每个 M 分区替换为旧版分区,并使其指向指定的(旧版)数据源。 它还会把原始 M 分区的 M 表达式赋值给新建旧版分区的“Query”属性——这当然是毫无意义的,因为旧版数据源无法理解 M 查询。 因此,你应该逐个检查每个分区并手动更新查询;或者在你的源表/视图与导入表同名的前提下,使用可选的第 4 步。

你也可以考虑修改脚本第 7 行,用不同方式构造旧版分区查询,从而省去逐个处理分区查询的麻烦。 但这要求你的模型中表格和/或分区的命名方式比较一致:

foreach(var partition in table.Partitions) partition.Query = "SELECT * FROM [tabular].[vw_" + partition.Name + "]";

此示例使用分区名称来构造查询。 因此,如果你的模型里有一个名为 ResellerSalesFY2019 的分区,那么查询将变为: SELECT * FROM [tabular].[vw_ResellerSalesFY2019]

最后,如果你不介意用 C# 做一些字符串处理,你也许可以“解析”原始 M 表达式,从中提取查询里使用的架构名和表名——但这已经超出本文讨论范围。

Related articles