Some time ago I wrote a post about how you can use the DISCOVER_CALC_DEPENDENCY DMV to get a list of all the tables, columns and relationships referenced by a DAX query. That’s really useful and indeed the new INFO.CALCDEPENDENCY DAX function allows you to do the same thing without all the complexity of calling a DMV. However this doesn’t quite give you everything you need to solve one important problem: which columns are touched when a DAX query runs? The INFO.CALCDEPENDENCY function gives you a list of all the columns used directly in a DAX query and it also gives you a list of all the columns needed by all the measures used in a DAX query. However it only gives you a list of the relationships used and these relationships also rely on columns. In this post I’ll show you how to get a list of all the columns that are touched by a DAX query.
For illustration, consider the following model:

Note that the relationship between the Product table and the Sales table is inactive. The definitions of the three measures are as follows:
Units = SUM(Sales[SalesUnits])
Value = SUM(Sales[SalesValue])
Apples Value =
CALCULATE (
[Value],
KEEPFILTERS ( 'Product'[ProductName] = "Apples" ),
USERELATIONSHIP ( 'Product'[ProductID], 'Sales'[ProductID] )
)
There is also a calculated column called CustomerID and Name defined as follows:
Customer ID and Name =
"(" & 'Customer'[CustomerID] & ") " & Customer[CustomerName]
Now consider the following visual:

The DAX query for this is as follows:
// DAX Query
DEFINE
VAR __DS0Core =
SUMMARIZECOLUMNS(
ROLLUPADDISSUBTOTAL('Country'[CountryName], "IsGrandTotalRowTotal"),
"Apples_Value", 'Sales'[Apples Value]
)
VAR __DS0PrimaryWindowed =
TOPN(502, __DS0Core, [IsGrandTotalRowTotal], 0, [Apples_Value], 0, 'Country'[CountryName], 1)
EVALUATE
__DS0PrimaryWindowed
ORDER BY
[IsGrandTotalRowTotal] DESC, [Apples_Value] DESC, 'Country'[CountryName]
Passing this query to INFO.CALCDEPENDENCY like so:
EVALUATE
VAR Source_Query =
"
DEFINE
VAR __DS0Core =
SUMMARIZECOLUMNS(
ROLLUPADDISSUBTOTAL('Country'[CountryName], ""IsGrandTotalRowTotal""),
""Apples_Value"", 'Sales'[Apples Value]
)
VAR __DS0PrimaryWindowed =
TOPN(502, __DS0Core, [IsGrandTotalRowTotal], 0, [Apples_Value], 0, 'Country'[CountryName], 1)
EVALUATE
__DS0PrimaryWindowed
ORDER BY
[IsGrandTotalRowTotal] DESC, [Apples_Value] DESC, 'Country'[CountryName]
"
VAR All_Dependencies =
INFO.CALCDEPENDENCY(
"QUERY",
Source_Query
)
RETURN All_Dependencies
[Note that all double quotes in the query being passed in have been escaped]
…returns all the measures, tables, columns and relationships used:

It knows that the Apples Value measure needs the SalesValue column and the ProductName column and it knows that the relationships between the Country table and the Sales table, and the Product table and the Sales table, are also required but it doesn’t tell you which columns those relationships in turn need. Luckily the new INFO.VIEW.RELATIONSHIPS() function can be used to get that extra information easily.
Here’s a more complex DAX query that returns a list of all the measures touched by a DAX query, including those needed by all the measures and all the relationships needed by that query:
EVALUATE
VAR Source_Query =
"
DEFINE
VAR __DS0Core =
SUMMARIZECOLUMNS(
ROLLUPADDISSUBTOTAL('Country'[CountryName], ""IsGrandTotalRowTotal""),
""Apples_Value"", 'Sales'[Apples Value]
)
VAR __DS0PrimaryWindowed =
TOPN(502, __DS0Core, [IsGrandTotalRowTotal], 0, [Apples_Value], 0, 'Country'[CountryName], 1)
EVALUATE
__DS0PrimaryWindowed
ORDER BY
[IsGrandTotalRowTotal] DESC, [Apples_Value] DESC, 'Country'[CountryName]
"
VAR All_Dependencies =
INFO.CALCDEPENDENCY(
"QUERY",
Source_Query
)
VAR Referenced_Cols =
SELECTCOLUMNS(
FILTER(
All_Dependencies,
[REFERENCED_OBJECT_TYPE] IN {"COLUMN", "CALC_COLUMN"}
),
"FullyQualifiedName",
"'" & [REFERENCED_TABLE] & "'[" & [REFERENCED_OBJECT] & "]"
)
VAR Referenced_Relationships =
SELECTCOLUMNS(
FILTER(
All_Dependencies,
[REFERENCED_OBJECT_TYPE] IN {"ACTIVE_RELATIONSHIP", "RELATIONSHIP"} ),
"Name",
[REFERENCED_OBJECT])
VAR Relationship_Details =
FILTER(
INFO.VIEW.RELATIONSHIPS(),
[Name] IN Referenced_Relationships
)
VAR Relationship_Columns =
UNION(
SELECTCOLUMNS(
Relationship_Details,
"FullyQualifiedName",
"'" & [FromTable] & "'[" & [FromColumn] & "]"
),
SELECTCOLUMNS(
Relationship_Details,
"FullyQualifiedName",
"'" & [ToTable] & "'[" & [ToColumn] & "]"
)
)
VAR All_Referenced_Columns =
UNION(
Referenced_Cols,
Relationship_Columns
)
RETURN
All_Referenced_Columns
Here’s what it returns:

As you can see, this returns a list of all the columns used directly by the query, any measures referenced by the query, and all the relationships involved too.
You can use this query very easily in DAX Query View: just paste it in, then capture the DAX query generated by your own visuals using Performance Analyzer, escape any double quotes and paste it into the Source_Query variable in the query above.
Here’s one more example of how it works, a visual that touches a lot more columns:

I won’t post the full DAX query of the visual or my query again, but here’s the list of columns returned by my query:

One thing to notice about this is that while it shows the calculated column [Customer ID and Name] is used, it doesn’t break down this column’s dependencies and therefore doesn’t list the [CustomerName] column. This is a deliberate decision on my part.
Why is all this useful? The obvious answer is that it would allow you to see whether a query would break or return a different result if you deleted a column from your model. More interestingly – and this is something I need to research more – given that in Direct Lake mode columns are paged into memory when needed by a query, and given that it’s possible to use other DMVs/INFO functions to get the size of a column in memory (for example as DAX Studio’s Model Metrics feature does), it should be possible to use this approach to find the total memory used by all the columns needed by a DAX query on a Direct Lake model. This would be very helpful when diagnosing memory errors in Direct Lake mode.
Hi Chris , What did you mean by this “[Note that all double quotes in the query being passed in have been escaped].”
I mean that every instance of a double quote character in the original query text has been replaced with two double quote characters, because the query text is stored as a string in my query (which of course means it needs to be surrounded by double quotes)
Is there a way to run this that just tells me all the columns that are used in ALL the measures or calculated columns in my model?
Hi Chris , If we want to automate and collect these attributes data from all the datasets in org from Power BI Service standpoint , do you see any API’s sourcing these data ?