DP-600 · Domain 3: Implement and manage semantic models · 23% of the exam
Task 3.1: Design and build semantic models
Storage modes including Direct Lake, uses for DAX Studio and Tabular Editor 2, star schemas, bridge tables and many-to-many relationships, DAX variables, iterators, table filtering, window and information functions, calculation groups, dynamic strings, field parameters, large semantic models, composite models with aggregations, and dynamic row-level and object-level security.
Study it
Choosing a storage mode: Import, DirectQuery, Direct Lake or composite
Calculation groups, dynamic format strings and field parameters
Lesson coming
Large semantic models and composite models with aggregations
Lesson coming
Dynamic row-level and object-level security, and validating it
Lesson coming
DAX Studio and Tabular Editor 2
Lesson coming
Sample questions
Try each one before opening the answer. Every option is explained, with the Microsoft documentation page that proves it.
Question 1 · choose 1
A warehouse enforces a SQL row-level security policy that limits each regional manager to the rows of their region in dbo.Sales. A team replaces the Direct Lake on SQL semantic model over it with a Direct Lake on OneLake model that reads the same tables through a cloud connection with a fixed identity. After the switch, every manager sees all regions in the reports. Managers must again see only their own region. What should you do?
ASwitch the model's Direct Lake behavior to DirectLakeOnly
BGrant the managers ReadData on the warehouse so the SQL policy applies to them
CTurn single sign-on on in the cloud connection, keeping the fixed identity for refreshes
DDefine the region filter as an RLS role in the semantic model
Show the answer and why
ASwitch the model's Direct Lake behavior to DirectLakeOnly
Incorrect
That setting applies only to Direct Lake on SQL, and on OneLake the queries already run without fallback; it doesn't bring back the SQL policy.
BGrant the managers ReadData on the warehouse so the SQL policy applies to them
Incorrect
Direct Lake on OneLake reads the Delta tables through OneLake and never evaluates the SQL policy, whoever queries.
CTurn single sign-on on in the cloud connection, keeping the fixed identity for refreshes
Incorrect
With SSO, queries would run as each manager and need their own OneLake access to the data, and the SQL policy still wouldn't be applied.
DDefine the region filter as an RLS role in the semantic model
Correct
Direct Lake on OneLake doesn't apply SQL-based RLS, so with a fixed identity the rule has to live in the model.
Direct Lake on OneLake isn't coupled with the SQL analytics endpoint: it reads Delta tables through OneLake, so row-level security defined in the SQL analytics endpoint or warehouse isn't applied and queries succeed. Data-access rules must then be defined in the semantic model or in OneLake security. Semantic model RLS is the recommended choice when report consumers have no permission on the source item and the cloud connection uses a fixed identity.
While developing a Direct Lake on SQL semantic model, you want any query that can't be answered in Direct Lake mode to fail with an error, so that you find and fix the cause before release, instead of quietly running in DirectQuery mode. Which Direct Lake behavior setting should the model use during development?
AAutomatic
BDirectLakeOnly
CDirectQueryOnly
DImport
Show the answer and why
AAutomatic
Incorrect
Automatic, the default, falls back to DirectQuery silently, which hides the cause.
BDirectLakeOnly
Correct
With DirectLakeOnly, a query whose Direct Lake conditions aren't met fails with an error, which is meant for development.
CDirectQueryOnly
Incorrect
DirectQueryOnly sends every query in DirectQuery mode; it's for measuring fallback performance.
DImport
Incorrect
Import isn't a value of the Direct Lake behavior setting; it's a different table storage mode.
The DirectLakeBehavior property applies to Direct Lake on SQL analytics endpoints. Automatic (the default) silently falls back to DirectQuery when Direct Lake conditions aren't met, which suits production. DirectLakeOnly makes such queries fail with an error, so you can identify and resolve problems during development. DirectQueryOnly always uses DirectQuery, for measuring fallback performance. You set it in the model's Properties pane or through TOM or TMSL.
Report visuals over a Direct Lake on SQL semantic model with 30 tables are slower than expected, and you suspect that some tables fall back to DirectQuery. You want to see, for every table at once, whether it uses Direct Lake and, if not, the reason. What should you run?
TABLETRAITS returns a row per table, and DirectLakeFallbackInfo shows the fallback reason, or None when Direct Lake is used.
DA refresh, with the model's Refresh history open on the Direct Lake tab
Incorrect
That tab lists Direct Lake refresh failures, not the per-table fallback reason of queries.
To identify which tables fall back to DirectQuery and why, run the DAX query EVALUATE TABLETRAITS(). Its DirectLakeFallbackInfo column shows the reason for each table, and None means the table uses Direct Lake mode. Common causes include unframed tables, tables based on SQL views, SQL security at the endpoint, guardrails exceeded and memory pressure, each with its own fix.
A developer writes Sales Red = VAR S = [Sales] RETURN CALCULATE(S, Product[Color] = "Red"). In a matrix by product category, every row shows the category's total sales for all colors, not the red sales. Why?
AS is computed before CALCULATE applies the filter, and a variable's value never changes
BCALCULATE can't take a Boolean filter on a column from another table
CVariables are evaluated once per query, so S holds the grand total of all categories
DRETURN must reference the measure directly; variables can't be used as CALCULATE's first argument
Show the answer and why
AS is computed before CALCULATE applies the filter, and a variable's value never changes
Correct
Variables are evaluated outside the filters that the RETURN expression applies, so S keeps the all-colors value.
BCALCULATE can't take a Boolean filter on a column from another table
Incorrect
A filter such as Product[Color] = "Red" is valid in CALCULATE; the issue is that S is already computed.
CVariables are evaluated once per query, so S holds the grand total of all categories
Incorrect
The variable is evaluated in each cell's filter context; that's why each row shows its own category's total.
DRETURN must reference the measure directly; variables can't be used as CALCULATE's first argument
Incorrect
A variable can be used there, but its value is a constant, so the filter has no effect on it.
After DAX calculates a variable's value, it doesn't change, even when you reference the variable in another expression. Variables are evaluated outside the filters your RETURN expression applies, so wrapping a variable in CALCULATE doesn't recalculate it under the new filters. To get red sales, apply the filter to the measure itself, for example VAR S = CALCULATE([Sales], Product[Color] = "Red").
A matrix shows Product[Category] and then 'Date'[Year] on rows, with [Sales] as values. A Prior Year Sales measure must return the previous year's sales of the same category, and blank for each category's first year rather than a value from another category. Which expression should the measure use?
Partitioning by year compares categories within a year instead of years within a category.
OFFSET returns a single row positioned before (negative delta) or after (positive delta) the current row within a relation, sorted by ORDERBY and split into partitions by PARTITIONBY. When the delta shifts to a row that doesn't exist within the partition, OFFSET returns an empty table, so the measure is blank for a category's first year. Without a partition, the whole relation is treated as one partition.
A model has two calculation groups: Time Intelligence, with a YTD item, and Currency Conversion, whose item multiplies SELECTEDMEASURE() by an exchange rate. When readers pick YTD and EUR, the result must be the year-to-date total of the daily converted amounts, and the current results show a different order of evaluation. What should you change?
AThe precedence of the two calculation groups
BThe ordinal values of the YTD and EUR calculation items
CA selection expression on Currency Conversion for when no currency is selected
DA dynamic format string on the EUR calculation item
Show the answer and why
AThe precedence of the two calculation groups
Correct
With several calculation groups, precedence decides the order in which they're applied to the measure.
BThe ordinal values of the YTD and EUR calculation items
Incorrect
Ordinals sort the items within a group for display; they don't change the order in which groups evaluate.
CA selection expression on Currency Conversion for when no currency is selected
Incorrect
Selection expressions control results for multiple, invalid or no selections, not the order of two selected items.
DA dynamic format string on the EUR calculation item
Incorrect
A format string changes how the result is displayed, not how the two calculations combine.
When a model has more than one calculation group, the precedence property specifies the order in which they apply to a measure, which matters when the calculations don't commute, such as time intelligence over a currency conversion. You set it in the Calculation groups section of the Properties pane. Ordinal sorts items within a group, selection expressions handle multiple, invalid or no selections, and dynamic format strings change formatting.
A Sales measure must show amounts with the currency symbol of the country selected in a slicer, such as € or ¥. A first attempt wraps the value in FORMAT with a format string looked up from a currency table: the numbers look right in a table visual, but the column chart over the measure no longer plots them. Charts must work, and the formatting must still follow the slicer. What should you do?
AKeep FORMAT and change the measure's data type to Decimal number in Measure tools
BCreate a calculation group with one item per currency
CReturn the number and move the currency lookup into a dynamic format string
DTurn the currency table into a field parameter
Show the answer and why
AKeep FORMAT and change the measure's data type to Decimal number in Measure tools
Incorrect
FORMAT returns text whatever data type you set, so the chart still has no numeric values to plot.
BCreate a calculation group with one item per currency
Incorrect
A calculation group could switch formats, but it applies to every measure and adds a slicer for the items; the requirement is one measure following the country slicer.
CReturn the number and move the currency lookup into a dynamic format string
Correct
A dynamic format string formats the measure by context while the measure keeps its numeric data type.
DTurn the currency table into a field parameter
Incorrect
Field parameters switch which fields a visual shows; they don't format a measure's values.
FORMAT returns all results as strings, even for numeric values, which causes problems with visuals such as charts that need numbers. With a dynamic format string for a measure, you write a separate DAX expression that returns the format string, for example from a table of currency format strings, and the measure keeps its data type. Calculation groups also support dynamic format strings, but their scope is every measure they're applied to.
A composite model keeps a 3-billion-row Sales table in DirectQuery against a warehouse. An Import table, Sales Agg, holds SalesAmount summed by DateKey, CustomerKey and ProductKey and is mapped in Manage aggregations, and the dimension tables use Dual storage mode. Sales by month and by customer segment hit the aggregation, but a Customers measure, DISTINCTCOUNT(Sales[CustomerKey]), always queries the warehouse. There are about 3 million customers. What should you change so that the measure can use Sales Agg?
ASet the Customer table to Import storage mode
BAdd a GroupBy entry for CustomerKey in Manage aggregations
CAdd a Count table rows entry for Sales in Manage aggregations
DSet the Sales Agg table to DirectQuery storage mode
Show the answer and why
ASet the Customer table to Import storage mode
Incorrect
Sums grouped by customer attributes already hit the aggregation, so the dimension's storage mode isn't what's missing for the distinct count.
BAdd a GroupBy entry for CustomerKey in Manage aggregations
Correct
With relationship-based aggregations, GroupBy entries matter only for DISTINCTCOUNT: a CustomerKey entry keeps the keys distinct in Sales Agg.
CAdd a Count table rows entry for Sales in Manage aggregations
Incorrect
Count table rows lets COUNTROWS queries hit the aggregation; it doesn't keep the customer keys distinct.
DSet the Sales Agg table to DirectQuery storage mode
Incorrect
Once an aggregation table is set to Import, its storage mode can't be changed again, and DirectQuery wouldn't make distinct counts hit it.
In relationship-based aggregations, GroupBy entries are optional and mostly there for readability: without them, aggregations are still hit through the relationships. DISTINCTCOUNT is the exception. A GroupBy entry for CustomerKey maintains the distinctness of CustomerKey in the aggregation table, so a distinct count of customers can be answered from it. This suits billions of detail rows with a few million distinct values; beyond about 2 to 5 million distinct values, performance can suffer.
In an import model, the Employee table has EmployeeID, ManagerID and Email columns for 4,000 employees in a hierarchy up to eight levels deep, and Sales relates to Employee on EmployeeID. Each manager must see the sales of every employee who reports to them directly or indirectly, plus their own, and the hierarchy changes weekly. Which RLS filter on Employee meets this?
PATH lists each row's chain of managers, and the row is kept when the signed-in user's ID is in that chain.
PATH returns a delimited string with the identifiers of all the parents of the current identifier, so for each employee it lists the chain of managers up to the top, including the employee. PATHCONTAINS returns TRUE when an item is in that path. Looking up the signed-in user's EmployeeID with USERPRINCIPALNAME and testing it against each row's path keeps every row in that manager's subtree. PATH and PATHCONTAINS aren't supported in RLS rules in DirectQuery mode.
A developer creates a new semantic model with Direct Lake tables in Power BI Desktop by picking tables from a lakehouse in the OneLake catalog. Which kind of Direct Lake model does she get?
ADirect Lake on SQL
BA DirectQuery model over the SQL analytics endpoint
CDirect Lake on OneLake
DAn Import model with OneLake integration
Show the answer and why
ADirect Lake on SQL
Incorrect
Direct Lake on SQL models are created from the SQL analytics endpoint page, not from Desktop.
BA DirectQuery model over the SQL analytics endpoint
Incorrect
Picking Direct Lake tables creates Direct Lake tables, not DirectQuery tables.
CDirect Lake on OneLake
Correct
Creating a Direct Lake model in Power BI Desktop supports Direct Lake on OneLake.
DAn Import model with OneLake integration
Incorrect
OneLake integration exports Import tables to OneLake; it isn't how Desktop builds Direct Lake tables.
Direct Lake semantic models can be created in Power BI Desktop, from the OneLake catalog in the service, or from a SQL analytics endpoint's page. Creation from Power BI Desktop and from the service supports Direct Lake on OneLake only; from the SQL analytics endpoint page you can choose Direct Lake on OneLake or Direct Lake on SQL.
A semantic model has an OLS role that hides the Salary column. Members of that role who hold the Contributor role in the workspace still see Salary, while Viewers in the role don't. Why?
AOLS applies only to Viewers; editors of the model aren't restricted
BOLS applies only in Power BI Desktop and isn't enforced for reports in the service
CThe Contributors opened the report from a different workspace
DOLS rules take a day to reach Contributors
Show the answer and why
AOLS applies only to Viewers; editors of the model aren't restricted
Correct
Workspace roles above Viewer have Edit permission on the semantic model, so OLS doesn't apply to them.
BOLS applies only in Power BI Desktop and isn't enforced for reports in the service
Incorrect
OLS is enforced in the service for users it applies to, which is why the Viewers don't see Salary.
CThe Contributors opened the report from a different workspace
Incorrect
The report's location doesn't change whether OLS applies to a user.
DOLS rules take a day to reach Contributors
Incorrect
There's no delay by role; OLS simply doesn't apply to editors of the model.
Object-level security secures tables or columns from report viewers, and for users without permission it's as if the objects don't exist. OLS only applies to Viewers in a workspace: members of the Admin, Member or Contributor roles have Edit permission on the semantic model, so OLS doesn't apply to them. OLS is defined in model roles, for example with TMDL view or Tabular Editor.
A matrix shows Product[Product] on rows, and a Position measure is defined as ROWNUMBER(ALLSELECTED(Product[Product]), ORDERBY([Sales], DESC)). Two products have exactly the same sales. What does Position return for those two products?
AThe same number for both, with the next product's number skipping one
BTwo consecutive numbers, with the tie broken by the product column
CBLANK for both products
DAn error, because the ORDERBY values tie at runtime
Show the answer and why
AThe same number for both, with the next product's number skipping one
Incorrect
ROWNUMBER returns a unique number for every row, so tied rows don't share a number.
BTwo consecutive numbers, with the tie broken by the product column
Correct
ROWNUMBER appends the fewest columns needed to make every row unique, here Product[Product], to its ORDERBY.
CBLANK for both products
Incorrect
ROWNUMBER is blank only when the current row can't be matched in the relation.
DAn error, because the ORDERBY values tie at runtime
Incorrect
An error is returned only when no additional columns can make every row unique; here Product[Product] can.
ROWNUMBER returns the unique ranking for the current context within the specified partition, sorted by the specified order, and returns blank if the current row can't be matched. If the orderBy and partitionBy columns can't uniquely identify every row in the relation, ROWNUMBER finds the least number of additional columns that do and appends them to orderBy; if no such columns exist and it detects a tie at runtime, it returns an error.
A diagnostic measure must return TRUE whenever Product[Category] is affected by any filter, whether the filter is on Category itself, on another Product column such as Color, or on a related table such as Sales. Which DAX function returns that?
AISFILTERED(Product[Category])
BISEMPTY(Product)
CHASONEVALUE(Product[Category])
DISCROSSFILTERED(Product[Category])
Show the answer and why
AISFILTERED(Product[Category])
Incorrect
ISFILTERED returns TRUE only when the column itself is filtered directly.
BISEMPTY(Product)
Incorrect
ISEMPTY tests whether a table expression returns no rows.
CHASONEVALUE(Product[Category])
Incorrect
HASONEVALUE tests whether exactly one distinct value remains, not whether a filter elsewhere affects the column.
DISCROSSFILTERED(Product[Category])
Correct
A column is cross-filtered when a filter applies to it, to any column of its table or to any column of a related table.
ISCROSSFILTERED returns TRUE when the specified column or table is cross-filtered, that is, when a filter is applied to the column, to any column of its table, or to any column of a related table. ISFILTERED returns TRUE only for direct filters on the column, and HASONEVALUE checks whether one distinct value remains. Neither ISCROSSFILTERED nor ISFILTERED is supported in DirectQuery mode in calculated columns or RLS rules.