By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Folding in Power BI is the process where Power Query pushes operations (filters, joins, aggregations) back to the data source (SQL Server, Oracle, etc.) instead of loading raw data and processing it locally. Non-folding means Power BI pulls raw data and processes it in-memory.
Why this matters in production:- Performance: A query that folds runs in milliseconds on a SQL Server but takes minutes (or crashes) if it pulls 10M rows into Power BI.- Cost: Non-folding queries spike memory usage, leading to premium capacity throttling or failed refreshes.- Scalability: A report that works fine with 10K rows fails in production with 10M rows if folding isn’t optimized.
Real-world scenario:You inherit a Power BI report that takes 20 minutes to refresh and crashes when filtering. The data source is SQL Server. The original developer wrote M code that looks like this:
let Source = Sql.Database("server", "db"), Data = Source{[Schema="dbo",Item="Sales"]}[Data], Filtered = Table.SelectRows(Data, each [OrderDate] >= #date(2023,1,1)) in Filtered
This doesn’t fold—Power BI pulls all rows from Sales before filtering. Fixing this could cut refresh time to 2 seconds.
Sales
Table.Buffer
Table.Profile
Bad (Non-Folding) Example:
let Source = Sql.Database("server", "db"), Sales = Source{[Schema="dbo",Item="Sales"]}[Data], Filtered = Table.SelectRows(Sales, each [OrderDate] >= #date(2023,1,1)), Grouped = Table.Group(Filtered, {"ProductID"}, {{"TotalSales", each List.Sum([Amount]), type number}}) in Grouped
Why it fails:- Table.Group doesn’t fold in most SQL sources.- Power BI pulls all rows before grouping.
Table.Group
Good (Folding) Example:
let Source = Sql.Database("server", "db"), Filtered = Sql.Database("server", "db", [Query="SELECT ProductID, SUM(Amount) AS TotalSales FROM dbo.Sales WHERE OrderDate >= '2023-01-01' GROUP BY ProductID"]) in Filtered
Why it works:- The entire operation is pushed to SQL Server.- Only the aggregated results are loaded into Power BI.
sql SELECT ProductID, SUM(Amount) AS TotalSales FROM dbo.Sales WHERE OrderDate >= '2023-01-01' GROUP BY ProductID
OrderDate
ProductID
Table.SelectColumns
powerquery let Source = Sql.Database("server", "db"), Sales = Source{[Schema="dbo",Item="Sales"]}[Data], SelectColumns = Table.SelectColumns(Sales, {"ProductID", "Amount", "OrderDate"}), Filtered = Table.SelectRows(SelectColumns, each [OrderDate] >= #date(2023,1,1)), Grouped = Table.Group(Filtered, {"ProductID"}, {{"TotalSales", each List.Sum([Amount]), type number}}) in Grouped
Table.SelectRows
✅ Always check folding before publishing.✅ Use View Native Query after every major step.✅ Push complex logic to SQL (stored procedures, views).✅ Avoid Table.Buffer unless you intentionally want to load data into memory.✅ Use Table.SelectColumns early to reduce data transfer.
View Native Query
? Non-folding queries spike memory usage → higher premium capacity costs.? DirectQuery reports with non-folding queries cause slow interactions → poor user experience.? Pre-aggregate data in SQL instead of in Power BI.
? Document folding assumptions (e.g., "This query folds because we use a SQL view").? Use Power BI Dataflows for non-folding sources (e.g., Excel, Web API).? Test with production-scale data (not just a sample).
? Monitor refresh durations in the Power BI Service.? Set up alerts for failed refreshes.? Use Query Diagnostics to identify bottlenecks.
Table.Schema
Table.AddColumn
Table.TransformColumns
❌ Table.SelectRows with a simple filter
"You have a DirectQuery report with slow performance. What’s the most likely cause?"
❌ Too many visuals on the page.
"How can you check if a query is folding?"
"You have a SQL Server table with 10M rows. A Power BI report takes 15 minutes to refresh. What’s the most likely fix?"- ✅ Rewrite the query to fold (push filtering/aggregation to SQL).- ❌ Increase the Power BI dataset size.- ❌ Use Table.Buffer to speed up processing.
You have this M query:
let Source = Sql.Database("server", "db"), Customers = Source{[Schema="dbo",Item="Customers"]}[Data], Orders = Source{[Schema="dbo",Item="Orders"]}[Data], Merged = Table.NestedJoin(Customers, "CustomerID", Orders, "CustomerID", "Orders", JoinKind.LeftOuter), Expanded = Table.ExpandTableColumn(Merged, "Orders", {"OrderID", "Amount"}, {"OrderID", "Amount"}), Filtered = Table.SelectRows(Expanded, each [Amount] > 1000) in Filtered
Problem: It’s slow and doesn’t fold.Task: Rewrite it to fold.
let Source = Sql.Database("server", "db", [Query=" SELECT c.*, o.OrderID, o.Amount FROM dbo.Customers c LEFT JOIN dbo.Orders o ON c.CustomerID = o.CustomerID WHERE o.Amount > 1000 "]) in Source
Why it works:- The entire join and filter is pushed to SQL Server.- Only the final result is loaded into Power BI.
Table.NestedJoin
Final Tip:Always ask: "Can the data source do this faster than Power BI?" If yes → fold it.If no → pre-process in SQL or a dataflow.
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.