best-practices
Applies Power BI best practices, BPA rules, and enterprise standards. Use for quality validation, naming conventions, and performance optimization.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Applies Power BI best practices, BPA rules, and enterprise standards. Use for quality validation, naming conventions, and performance optimization.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | best-practices |
| description | Applies Power BI best practices, BPA rules, and enterprise standards. Use for quality validation, naming conventions, and performance optimization. |
This skill helps apply Power BI best practices, Best Practice Analyzer (BPA) rules, and enterprise standards to semantic models and reports.
BPA rules are organized into categories:
/ operatorBi-directional relationships cause performance overhead and can create ambiguity.
Instead of:
relationship {{guid}}
fromColumn: TableA.'Key'
toColumn: TableB.'Key'
crossFilteringBehavior: bothDirections
Do this:
relationship {{guid}}
fromColumn: TableA.'Key'
toColumn: TableB.'Key'
// Use DAX CROSSFILTER() in measures when needed
measure 'Filtered Value' =
CALCULATE(
[Base Measure],
CROSSFILTER(TableA[Key], TableB[Key], Both)
)
Integer comparisons are faster than string comparisons.
Instead of:
column 'Product Key'
dataType: string
Do this:
column 'Product Key'
dataType: int64
Calculated columns consume memory and slow refresh. Use measures when possible.
Instead of calculated column:
column 'Profit Margin' =
DIVIDE(Sales[Profit], Sales[Revenue], 0)
Use a measure:
measure 'Profit Margin' =
DIVIDE(SUM(Sales[Profit]), SUM(Sales[Revenue]), 0)
Unused columns waste memory. Delete columns not used in:
Columns with many unique values increase model size. Consider:
| Data | Recommended Type |
|---|---|
| IDs, Keys | int64 |
| Flags | boolean |
| Currency | decimal |
| Percentages | double or calculated in DAX |
| Dates | dateTime |
/Bad:
Margin = Sales[Profit] / Sales[Revenue]
Good:
Margin = DIVIDE(Sales[Profit], Sales[Revenue], 0)
Bad:
Growth % =
(SUM(Sales[Amount]) - CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR(Date[Date])))
/ CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR(Date[Date]))
Good:
Growth % =
VAR CurrentSales = SUM(Sales[Amount])
VAR PriorSales = CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR(Date[Date]))
RETURN
DIVIDE(CurrentSales - PriorSales, PriorSales)
/// Calculates total sales revenue
/// Excludes returns and cancellations
measure 'Total Sales' =
SUM(Sales[Amount])
IFERROR masks data quality issues.
Bad:
Total = IFERROR(SUM(Sales[Amount]), 0)
Good:
Total = SUM(Sales[Amount])
// Handle blanks explicitly if needed
Total = COALESCE(SUM(Sales[Amount]), 0)
REMOVEFILTERS is more explicit about intent.
Prefer:
All Sales = CALCULATE([Total Sales], REMOVEFILTERS(Products))
Deeply nested CALCULATE is hard to maintain.
Bad:
Measure =
CALCULATE(
CALCULATE(
CALCULATE([Base], Filter1),
Filter2
),
Filter3
)
Good:
Measure =
CALCULATE(
[Base],
Filter1,
Filter2,
Filter3
)
| Pattern | Example | Use |
|---|---|---|
| PascalCase | SalesOrders | Standard tables |
| Singular | Customer not Customers | Dimension tables |
| Prefix dim/fact | dimCustomer, factSales | Optional, for clarity |
| Pattern | Example |
|---|---|
| PascalCase with spaces | Customer Name |
| Keys end with Key | Product Key |
| IDs end with ID | Transaction ID |
| Dates end with Date | Order Date |
| Category | Pattern | Example |
|---|---|---|
| Aggregations | Noun phrase | Total Sales |
| Percentages | End with % | Gross Margin % |
| Ratios | Include units | Sales per Customer |
| Time Intelligence | Include period | Sales YTD, Sales PY |
| Counts | End with Count | Customer Count |
Organize measures into logical folders:
├── Core Metrics
│ ├── Total Sales
│ ├── Total Cost
│ └── Total Profit
├── Time Intelligence
│ ├── Sales YTD
│ ├── Sales PY
│ └── Sales YoY %
├── Percentages
│ ├── Gross Margin %
│ └── % of Total
└── KPIs
├── Target
└── Achievement
Delete these if not used:
Every object should have a description:
/// Customer dimension table
/// Contains customer demographics and segmentation
table Customers
lineageTag: ...
/// Unique identifier for each customer
column 'Customer ID'
...
/// Customer's full name (First + Last)
column 'Customer Name'
...
Before creating relationships, verify:
Before using measures in visuals:
Consider these scenarios:
Define RLS roles in TMDL:
role SalesRep
modelPermission: read
tablePermission Sales = 'Sales'[Sales Rep] = USERPRINCIPALNAME()
Mark sensitive columns:
column 'SSN'
dataType: string
isHidden
// Consider not including in model
Document model changes:
NEVER store credentials in source files:
/// BAD: Hardcoded connection string
expression ConnectionString = "Server=prod.database.com;User=admin;Password=secret123"
/// GOOD: Use parameters without credentials
expression ServerName = "prod.database.com" meta [IsParameterQuery=true, Type="Text"]
Credentials should be:
Use parameters for environment-specific values:
/// Server name parameter (update per environment)
expression ServerName = "dev-server.database.windows.net" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]
/// Database name parameter
expression DatabaseName = "SalesDB_Dev" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]
For on-premises or VNet data sources:
| Source Location | Gateway Required |
|---|---|
| Cloud (Azure SQL, SharePoint Online) | No |
| On-premises (SQL Server, file share) | Yes |
| VNet (private endpoints) | Yes (VNet gateway) |
| Local files (CSV, Excel) | Yes or use cloud storage |
Import Mode:
DirectQuery:
Hybrid (Composite):
RangeStart = #datetime(2020, 1, 1, 0, 0, 0) meta [IsParameterQuery=true, Type="DateTime"]
RangeEnd = #datetime(2025, 12, 31, 23, 59, 59) meta [IsParameterQuery=true, Type="DateTime"]
Table.SelectRows(Source, each [Date] >= RangeStart and [Date] < RangeEnd)
Ensure transformations push to source database:
| Foldable (DO) | Non-Foldable (AVOID) |
|---|---|
Table.SelectRows (simple) | Table.AddColumn (custom) |
Table.SelectColumns | Table.Buffer |
Table.Sort | Custom functions |
Table.Group | Cross-source joins |
Check folding: Right-click step > "View Native Query"
After creating tables
After adding relationships
After writing measures
Before deployment
After using other skills, apply best practices:
| Skill | Validation Focus |
|---|---|
pbip-project | File structure, encoding |
semantic-model | Relationships, data types |
dax | Measure quality, formatting |
report-visuals | Visual references, performance |
power-query | Query folding, data source parameters |
themes | Accessibility, color contrast |
calculation-groups | Appropriate use, format strings |
security | RLS filter efficiency, complete coverage |
deployment | BPA in CI/CD, secret management |
See bpa-rules.md for complete rule list.
See naming-conventions.md for detailed naming guidelines.
Creates calculation groups for reusable DAX patterns like time intelligence and currency conversion. Use to replace repetitive measures with dynamic calculations.
Writes DAX measures, calculated columns, and calculations for Power BI. Use for business logic, time intelligence, and analytical calculations.
Implements CI/CD pipelines and DevOps practices for Power BI. Use for automated validation, testing, and deployment of PBIP projects.
Creates and manages Power BI Desktop Project (PBIP) structure. Use when starting new Power BI projects, setting up folder structure, or configuring project files.
Writes Power Query (M language) for data transformation, connections, and ETL. Use for data sources, transformations, parameters, and query optimization.
Creates Power BI reports and visuals in PBIR format. Use for pages, charts, tables, slicers, and visual configuration.