
简介《DAX权威指南》第二版英文原版PDF由Marco Russo与Alberto Ferrari合著、微软授权Pearson出版面向数据分析师、商业智能开发者及使用Power BI、SQL Server Analysis Services与Excel构建分析方案的技术人员帮助系统掌握DAX数据建模与计算语言。全书从DAX基础语法、表函数与求值上下文讲起深入CALCULATE、SUMX、FILTER等核心函数、表间关系与多对多建模、上下文转换等高级特性并覆盖性能优化、最佳实践与真实案例研究兼顾入门理解与进阶实战。资源包共1个PDF文件大小约13.03MB内容完整、便于本地检索与离线阅读。目前已有827人学习下载适合希望从函数用法走向模型设计与查询优化的读者按章节精读也可作为日常DAX开发中的案头参考。1. 一份把 DAX 讲透的英文原版为什么它值得放在手边如果你写过CALCULATE却说不清它到底改了哪一层筛选上下文如果你用SUMX算出来的数对不上只能靠反复试错去凑如果你打开性能分析器看到一堆CallbackDataID就头皮发麻——那这份《DAX 权威指南》第二版英文原版 PDF基本就是给你准备的。它不是函数字典而是一本把 DAX 求值机制从底层拆开讲的书筛选上下文、行上下文、上下文转换、计算组、DAX 引擎、VertiPaq 存储、查询计划一条线拉到底。全书 20 章、700 多页覆盖 Power BI、SQL Server Analysis Services 表格模型和 Excel 三套宿主环境。适合已经能写度量值、但一遇到结果不对/慢得离谱就卡壳的从业者也适合想从会写跨到知道为什么这么写的建模人员。英文原版的好处是术语和官方文档完全对齐查资料时不用做二次翻译。2. 先立住求值模型上下文、CALCULATE 与上下文转换DAX 的坑九成出在这段表达式在什么上下文里求值这个问题上。这本书前五章几乎都在围绕这一件事反复碾压而这也正是它区别于普通教程的地方——先把模型讲清楚再谈函数怎么用。2.1 两种上下文筛选上下文与行上下文筛选上下文filter context是度量值求值时当前生效的一组筛选条件来自切片器、视觉对象的分组、矩阵的行列标题以及CALCULATE显式加上的筛选器。行上下文row context则出现在计算列和迭代函数内部表示当前正在处理哪一行。关键区别在于行上下文不会自动筛选模型。在计算列里写SUM(Sales[Amount])拿到的是整张表的总和不是当前行的值——因为行上下文只提供当前行这个概念不提供筛选。这一点书里用了一整节的对照实验来讲我建议照着做一遍-- 计算列行上下文存在但不产生筛选 Total All Sales SUM ( Sales[Amount] ) -- 想要当前行的值直接引用列即可 Line Amount Sales[Quantity] * Sales[UnitPrice]第一行返回的是全表合计第二行才是逐行计算。很多新手把这两者混为一谈结果在计算列里写聚合函数得到一列一模一样的数字还以为是软件出问题。书里对此的判断很直接计算列里出现聚合函数先怀疑是不是漏了上下文转换。2.2 CALCULATE 到底做了什么CALCULATE是 DAX 里唯一能修改筛选上下文的函数它的行为可以拆成三步先复制当前筛选上下文再用参数里的筛选器覆盖或叠加最后在新的上下文里求值第一个参数。书里第 5 章把这三步拆得很细尤其是覆盖和叠加的区别——直接写Sales[Color] Red是覆盖该列上已有的筛选而KEEPFILTERS包裹后变成叠加取交集。Red Sales CALCULATE ( SUM ( Sales[Amount] ), Sales[Color] Red -- 覆盖 Color 列上原有筛选 ) Red Sales Keep CALCULATE ( SUM ( Sales[Amount] ), KEEPFILTERS ( Sales[Color] Red ) -- 与原有筛选取交集 )参数说明第一个参数必须是返回标量的表达式后续参数可以是布尔表达式、表表达式或USERELATIONSHIP、CROSSFILTER这类关系修饰符。逻辑上CALCULATE会先做上下文转换见下一节再应用筛选器最后求值。顺序搞反百分比类度量值就会算错——书里用占总额比这个经典例子演示了ALL与ALLSELECTED的差异分母选错整张报表的占比全歪。2.3 上下文转换行上下文如何变成筛选上下文上下文转换是 DAX 最反直觉的机制在行上下文里调用CALCULATE或任何带CALCULATE语义的度量值引用DAX 会把当前行的每一列值转成等价的筛选条件作用到模型上。这就是为什么在迭代函数里引用度量值能拿到当前行对应的结果。-- 逐行计算每个产品的销售额占该品类总额的比例 Product Share SUMX ( VALUES ( Product[ProductKey] ), DIVIDE ( [Total Sales], -- 度量值触发上下文转换 CALCULATE ( [Total Sales], ALL ( Product ) ) -- 清空产品维度筛选 ) )逻辑说明SUMX在VALUES(Product[ProductKey])上建立行上下文每次迭代时[Total Sales]作为度量值被调用触发上下文转换把当前产品键转成筛选条件分母用ALL(Product)清掉产品维度上的所有筛选得到品类总额。参数上要注意ALL的范围——只清Product表还是清整张事实表结果完全不同。书里第 7 章专门讲迭代器与CALCULATE的组合核心结论是迭代器的基数cardinality直接决定性能能在粒度更细的表上迭代就别在宽表上迭代。2.4 变量让复杂表达式可读、可复用第 6 章讲VAR看似简单实则有两个容易翻车的点变量是常量定义后不会随上下文变化变量的作用域只在定义它的表达式内。书里强调惰性求值——变量只在被引用时才计算且只算一次。Sales YoY % VAR CurrentSales [Total Sales] VAR PriorSales CALCULATE ( [Total Sales], SAMEPERIODLASTYEAR ( Date[Date] ) ) RETURN DIVIDE ( CurrentSales - PriorSales, PriorSales )这里CurrentSales和PriorSales各算一次DIVIDE里复用不会重复求值。参数上注意SAMEPERIODLASTYEAR依赖标记为日期表的连续日期列日期表不连续或没标记这个函数会直接报错。我一般会在模型里先确认日期表被标记再写时间智能省得后面排查半天。3. 把计算组和时间智能落到模型里从写法到结构求值模型立住之后这本书的重心转向怎么组织计算。第 8 章时间智能、第 9 章计算组、第 10 章筛选上下文操作是实际项目里复用率最高的三块。它们的共同点是写法不难难在模型结构要配合。3.1 时间智能的前提一张合格的日期表时间智能函数TOTALYTD、SAMEPERIODLASTYEAR、DATEADD等全部依赖一张标记为日期表的连续日期维度且与事实表通过日期列建立一对多关系。书里反复强调日期表必须覆盖事实表的全部日期范围不能有断档否则年初累计、同比这类计算会在边界上出错。Sales YTD TOTALYTD ( [Total Sales], Date[Date] ) Sales PY CALCULATE ( [Total Sales], SAMEPERIODLASTYEAR ( Date[Date] ) )参数说明TOTALYTD第二个参数是日期列第三个可选参数是财年结束日如06-30做非自然年财年时必须传否则累计起点会错。SAMEPERIODLASTYEAR返回的是去年同期的一组日期本质是DATEADD(..., -1, YEAR)的语法糖。常见误用是把事实表里的日期列直接传给这些函数——必须用日期维度表的列否则筛选传播路径不对结果会莫名其妙地偏。3.2 计算组把同比、环比、累计从度量值里抽出来第 9 章的计算组是第二版相对第一版最重要的增补之一。传统做法是给每个基础度量值各写一套同比、环比、YTD度量值数量爆炸计算组把这些计算行为抽成独立的一列通过SELECTEDMEASURE()动态作用到任意度量值上。-- 计算项同比 VAR CurrentValue SELECTEDMEASURE () VAR PriorValue CALCULATE ( SELECTEDMEASURE (), SAMEPERIODLASTYEAR ( Date[Date] ) ) RETURN DIVIDE ( CurrentValue - PriorValue, PriorValue )逻辑说明SELECTEDMEASURE()返回当前被计算组作用的基础度量值计算项本身不绑定具体度量值所以一套同比逻辑可以服务所有度量值。参数上要注意计算组的优先级precedence——多个计算组同时作用时优先级决定应用顺序设错会导致先算占比再算同比还是先同比再占比的差异结果完全不同。书里给了优先级冲突的排查方法我一般会把时间类计算组设高优先级占比类设低避免嵌套顺序混乱。3.3 筛选上下文的精细操作ALLSELECTED 与 KEEPFILTERS第 10 章处理的是报表内占比这类需求。ALLSELECTED恢复的是视觉对象外部切片器等的筛选忽略视觉对象内部的分组ALL则清掉一切。两者在占比分母上的差异是报表数字对不上的高频原因。Share of Selected DIVIDE ( [Total Sales], CALCULATE ( [Total Sales], ALLSELECTED ( Product ) ) )这段在矩阵里按产品分组时分母是当前切片器选中的产品总额而不是全部产品总额。如果把ALLSELECTED换成ALL分母变成全量占比立刻偏小。书里用一张对照表列出了ALL、ALLSELECTED、ALLEXCEPT、REMOVEFILTERS在不同场景下的行为差异建议直接抄下来贴在显示器边上。4. 性能这条线DAX 引擎、VertiPaq 与查询计划前几章解决算得对第 17 到 20 章解决算得快。这部分是全书技术密度最高的地方也是很多读者买这本书的真正原因——网上讲 DAX 语法的资料一大把讲清楚存储引擎和查询计划的极少。4.1 两个引擎公式引擎与存储引擎DAX 查询由公式引擎Formula EngineFE和存储引擎Storage EngineSE协作完成。FE 负责解析表达式、做上下文转换、处理迭代逻辑SE 负责从 VertiPaq 列式存储里取数、做简单聚合。性能问题的通用判断是SE 查询多而快通常没问题FE 占用高、SE 查询少而慢往往是表达式写法导致 FE 做了大量逐行运算。书里第 17 章把两个引擎的分工讲得很清楚SE 只认简单的列筛选和聚合复杂逻辑一律回 FE。所以优化方向通常是把能下推给 SE 的运算下推比如用SUMX替代逐行IF嵌套用关系筛选替代FILTER全表扫描。4.2 VertiPaq 存储为什么列的顺序和基数很重要第 18 章讲 VertiPaq 的压缩机制列式存储、字典编码、值编码、游程编码RLE。核心结论是——列的基数distinct 值数量越低压缩率越高扫描越快。这直接影响建模决策高基数的列如订单号、时间戳尽量别放进维度表做分组能拆成低基数属性的别合并成一个长文本列。列类型典型基数压缩效果建模建议日期键整数数千好保留用于关系产品名称数百到数千中可作维度属性订单号百万级差避免用于分组自由文本备注极高极差不进入模型书里还提到计算列的基数如果很高会显著拖慢刷新和查询能用度量值表达的尽量别落成计算列。4.3 读查询计划从 CallbackDataID 找性能瓶颈第 19 章教你怎么看 DAX Studio 里的查询计划。最该警惕的信号是CallbackDataID——它意味着 SE 无法独立完成运算必须回调 FE 逐行处理通常出现在FILTER里引用了度量值、或迭代器内部做了复杂判断的场景。-- 反例FILTER 内引用度量值容易触发 CallbackDataID Bad Measure CALCULATE ( SUM ( Sales[Amount] ), FILTER ( Product, [Total Sales] 1000 ) ) -- 改进把条件改成列级筛选尽量下推给 SE Better Measure CALCULATE ( SUM ( Sales[Amount] ), FILTER ( ALL ( Product[ProductKey] ), [Total Sales] 1000 ) )逻辑说明第一版在整张Product表上迭代并逐行调用度量值FE 负担极重改进版把迭代范围收窄到单列减少物化开销。参数上注意FILTER的第一个参数尽量用单列或ALL后的窄表别直接传整张宽表。书里第 20 章给了完整的优化清单从减少物化表、避免嵌套迭代到用变量缓存中间结果逐条都有对应的查询计划对照。5. 避坑与排查五条血泪经验书读得再顺落到自己的模型上照样翻车。下面这几条是我在实际项目里反复撞到的配合书里的章节对照看能省不少时间。现象一计算列里聚合函数返回全表合计。原因行上下文不产生筛选聚合函数看到的是整表。解决要么直接引用列做逐行运算要么用CALCULATE触发上下文转换参考第 4、5 章的对照实验。现象二占比类度量值在矩阵里分母不对。原因ALL和ALLSELECTED用混分母范围超出或小于视觉对象。解决先明确分母要不要受切片器影响要就ALLSELECTED不要就ALL并用第 10 章的对照表逐项核对。现象三时间智能函数报日期列不连续或结果偏移。原因日期表没标记、有断档或把事实表日期列传给了函数。解决检查日期表标记状态、补齐连续日期、确认关系方向参考第 8 章。现象四报表打开慢查询计划里全是 CallbackDataID。原因FILTER内引用度量值或迭代宽表FE 逐行回调。解决收窄FILTER迭代范围到单列把能下推的运算改成列级筛选参考第 19、20 章。现象五多个计算组叠加后结果不符合预期。原因计算组优先级设置冲突应用顺序与预期相反。解决明确各计算组的职责边界按时间类高、占比类低排优先级用第 9 章的排查方法逐层验证。提示以上五条里前三条属于算错后两条属于算慢/算乱。排查顺序建议先对结果、再查性能别一上来就翻查询计划。6. 把这本书用成工具书我的翻阅习惯700 多页的英文原版通读一遍不现实也没必要。我的用法是把它当查证手册写度量值卡住时翻第 4、5 章对上下文做时间智能翻第 8 章性能出问题直接跳到第 17 到 20 章看查询计划那一节。第二版新增的计算组第 9 章和高级关系第 15 章值得单独精读这两块是近几年表格模型里变化最大、网上资料最零散的部分。一个具体技巧每读完一个机制就在自己的模型里造一个最小复现。比如学上下文转换就建一张两列的小表和一条关系写一个SUMX套度量值用 DAX Studio 看查询计划里 SE 和 FE 各干了什么。书里的例子再清楚也不如自己模型里跑一遍记得牢。英文原版还有个隐性好处——函数名、错误信息、查询计划里的术语和官方文档一字不差遇到报错直接搜原文命中率比搜翻译高得多。我自己的习惯是每次新建模型先把日期表标记好、关系方向确认一遍再动第一个度量值。这个动作看着琐碎但省下的排查时间远超那几分钟——毕竟 DAX 的坑多半不是函数写错而是模型结构没铺好。从那以后我每次开新模型都强制走一遍这个检查翻车次数肉眼可见地少了。希望帮到你。本文还有配套的精品资源点击获取