Unused Columns
Detects columns whose name does not appear anywhere in the report Layout — that is, columns that are not bound to any report visual, filter, or slicer (and are not pulled in transitively by the DAX of a measure or calculated column that is itself used).
What It Detects
This flag identifies individual columns in a semantic model that the analyzer cannot find any usage for in the report Layout. Usage is determined by scanning the serialized Report/Layout JSON for the column's short name (the part inside [...]) across the reference fields a visual binding can use — Property, Column, Name, Measure, queryName, queryRef, NativeReferenceName, Restatement, displayName, and Table[Column] / Table.Column patterns.
A column is treated as used when either of the following holds:
- Its short name matches one of those Layout reference patterns (it is bound to a visual, filter, slicer, or conditional-formatting rule), or
- It is referenced in the DAX expression of a measure or calculated column that is itself already marked used. The analyzer runs a fixed-point pass that follows these DAX references transitively (A → B → C).
Anything else is flagged as unused.
WARNING
The analyzer does not inspect relationships or sort-by-column configuration when deciding usage. A column that is used only as a relationship key, only as another column's sort-by column, or only inside an otherwise-unused measure will be flagged as unused even though it is not truly safe to delete.
WARNING
Soterre PBI Analyzer currently checks usage against one semantic model–report pair at a time (unless sibling report layouts are supplied for cross-report detection). In Power BI Service, a single semantic model can be connected to multiple reports. A column that appears unused in one report may be actively used in another report built on the same model. Keep this in mind before removing any flagged columns.
Why It Matters
- Memory waste — Each column is compressed and stored in the VertiPaq engine. High-cardinality text columns can consume hundreds of megabytes even when never queried.
- Slower refresh — Columns are processed during refresh regardless of usage, adding time and CU consumption.
- Model bloat — Unused columns inflate the model size, bringing it closer to SKU size limits.
- Developer confusion — A model with many unused columns is harder to navigate and understand.
Trigger Conditions
A column is flagged as unused when all of the following are true:
- The column's short name does not match any reference pattern in the report Layout JSON (it is not bound to any visual, filter, or slicer).
- The column is not referenced in the DAX of a measure or calculated column that is itself used (transitive dependency).
- The column's parent table is not an auto-hidden or auto-date helper table — columns inside those system tables are never flagged (their
isUnusedflag is force-cleared).
Threshold: Zero Layout matches for the column name and no transitive DAX usage from a used measure or calculated column.
Relationships, sort-by-column configuration, and the expressions of unused measures/calculated columns are not analyzed, so usage detected by this flag is effectively report-visual usage only.
Output
Each column in the analysis result is a ReportColumnDefinition object with the following fields:
| Field | Description |
|---|---|
name | Fully-qualified column name in Table[Column] form (e.g. Sales[Amount]) |
tableName | Parent table of the column |
dataType | Raw data type string from the model (e.g. string, int64, Integer, Text) |
estimatedRowCount | Assumed row count used for size estimation (a fixed 10,000 placeholder) |
estimatedSizeKB | Heuristic in-memory size in kilobytes, derived from data type and the assumed row count |
isUnused | true when the column matched no usage (this flag) |
isDuplicated | true when the same short column name appears in more than one table |
isCalculated | true when the column is a calculated column / calculated-table column |
expression | The DAX expression for calculated columns (omitted for regular columns) |
Note:
estimatedRowCountis always10,000andestimatedSizeKBis a rough heuristic — two columns with the same data type will always show the same estimated size. There is no cardinality, dataset-name, or workspace-name field on the column output.
Notes and Edge Cases
- Columns used only in relationships or DAX — Because relationships are never inspected and only used measures/calculated columns propagate usage, a column used solely as a relationship key, or referenced only by a measure that is itself not placed on any visual, will be flagged as unused. There is no relationship-based or standalone-DAX exemption.
- Auto-hidden / auto-date helper tables — Columns inside system-generated helper tables (
LocalDateTable_*, date-hierarchy and similar auto-generated tables) are never flagged as unused; the dedicated Auto-Hidden / Auto-Date signals cover those tables instead. - Columns used in Power Query only — If a column is used in a Power Query step but not exposed to the model, it is not flagged (it does not exist in the model).
- Implicit measures — Columns dragged directly onto a visual for implicit aggregation appear in the Layout as visual bindings, so they are detected as "used" and not flagged.
Related Flags
- Unused Tables — If every column in a table is unused, the entire table is flagged instead.
- Unused Measures — Similar check but for measures rather than columns.