Listen "Dataverse Deep Dive: Designing Scalable Data Models"
Episode Synopsis
What if the reason your Dataverse app slows to a crawl isn’t the size of your data… but the way your relationships are wired?Today, we’re going to break down the hidden connection between schema design and real-world responsiveness — and why so many Power Platform makers unknowingly lock themselves into poor performance from day one.The Hidden Performance Traps in Your TablesEver wonder why a table with only a few thousand rows feels slower than one with a million? It’s one of those moments where your gut tells you it should be fine, but Dataverse is acting like it’s moving through wet cement. The surprising truth is that it’s not the raw size that drags your app down — it’s the way the table is designed in the first place. And those design decisions start causing problems long before you run into any actual platform limits. A lot of makers blame external factors. They assume their tenant is throttled, the network is unstable, or there’s some hidden storage bottleneck in the service. But in many cases, those slow forms, laggy lookups, and Power Automate flows that keep timing out can all be traced back to a schema that looked perfect in the build phase but was structured in a way that slows down every single query touching it. If you’ve ever had a user complain about “Dataverse being slow” without adding any context, there’s a good chance the real culprit is your table layout. Think about it like a filing cabinet. If every drawer is crammed with papers and nothing is labeled, it doesn’t matter if there are only fifty files inside — you’re still going to waste time digging through it. A Dataverse table works the same way: bloated with fields you rarely use, stitched together with unnecessary relationships, it can make even simple data operations crawl. And unlike a messy cabinet, the mess here isn’t immediately visible to you or the user — the only symptom is a mounting performance penalty. I’ve seen projects where the table schema read like a “greatest hits” of every request from every stakeholder. Need a field for internal notes in three different formats? Done. A dozen variations of the same lookup in case someone needs it later? Add it in. Over time, these fields become dead weight. They get indexed when they don’t need to be, they slow down inserts and updates, and they make the form UI heavier than it should be. One real example involved a customer table with more than 250 fields, most of which existed “just in case.” The result? A form that took over 12 seconds to load on a high-speed connection — and that was before any automation kicked in. Microsoft’s own documentation spells out the trade-offs in normalization. By the book, breaking data into many smaller related tables protects against redundancy. In practice, over-normalizing can hurt Dataverse performance if normal operations require too many joins across those tables. Every join is extra work for the query engine — and if you’ve got columns that hardly ever change stored in separate related tables, you’re paying a processing cost without any real benefit. Pruning non-critical fields isn’t glamorous work, but it pays off quickly. Identify attributes that aren’t used in reporting, rarely change, or duplicate information elsewhere. Keep only what serves an actual process today, not what might be needed “one day.” Same with normalization — it’s worth reviewing where you can combine related but low-activity data to reduce joins. The goal isn’t to throw out good design principles, it’s to strike a balance between theory and the way your app actually runs under load. The reality is that scalable performance doesn’t come from throwing more resources at Dataverse — it starts with a schema designed for purpose. Lean tables execute faster, forms load more predictably, and automation triggers on time, even as your environment grows. Every unnecessary field or poorly thought-out normalization choice adds a little more friction to every query. Over time, that friction adds up to noticeable lag. Now that the clutter factor is out in the open, the next challenge hides in how your tables interact with each other — and that’s where relationship design can make or break performance.When Relationships Turn Into RoadblocksSome Dataverse relationships are like rush-hour junctions — everything bottlenecks in one spot, and the whole flow slows to a crawl. On paper, the data structure looks clean and logical. But in practice, a single overloaded join point can bring an entire model-driven app to its knees. This isn’t about bad data or huge volumes; it’s about how the relationships are wired under the hood. Relationship design can quietly introduce performance problems that only show up when you hit real-world scale. In smaller test environments, even inefficient joins run fine. Roll the same design out to an enterprise environment with thousands of active users and interconnected processes, and suddenly forms take seconds to load, subgrids time out, and anything touching those linked tables feels sluggish. These aren’t mysterious “cloud slowdowns” — they’re the natural result of relationships designed for clarity without factoring in how Dataverse actually executes queries. I’ve seen this firsthand in a project using a many-to-many relationship to link contacts to multiple service plans. In early testing, with a few hundred records, everything was smooth. But once the live data set grew into the hundreds of thousands and users were querying those links daily, that many-to-many table turned into the slowest part of the system. Every form load was triggering complex joins across three tables, each join adding more overhead until basic operations took far longer than expected. The hidden cost isn’t just in the joins themselves. Lookup fields in Dataverse can carry cascading behaviors — like automatic record reassignments, deletions, or updates — that run every time the linked record changes. While those are great for keeping data in sync, they also mean more background processing each time an update happens, even for fields unrelated to the main operation. In high-activity tables, those cascades can stack up quickly, reducing throughput and slowing interactions without an obvious visible trigger. Microsoft’s own guidance urges avoiding unnecessary complex joins, and for good reason. Every additional join in a query forces the Dataverse engine to do more work, translate more data, and keep more information in memory while it evaluates conditions. This is manageable in small doses, but once you start layering multiple many-to-many relationships and cascades into the same process, the execution time scales up much faster than you’d expect. One particularly revealing case involved changing a relationship from many-to-many to a single lookup with a supporting choice field. The business logic was slightly reworked so it didn’t require dynamically resolving multiple linked records, and the result was an immediate 80% reduction in form load time. That improvement wasn’t because the dataset shrank or the hardware got better — it was entirely down to giving Dataverse a simpler and more direct path to the information it needed. Alternate designs like flattening structures can also pay off. Sometimes a piece of data doesn’t need to live in its own dedicated related table. If it’s low-maintenance and changes infrequently, storing it directly in the main record as a choice field means one less join on retrieval. Similarly, some link tables can be replaced by calculated or rollup fields if they’re mainly used to display summarized information. That keeps the presentation layer fast while avoiding heavy query operations in the background. The takeaway here is that relationship design isn’t just about logical clarity or meeting normalization standards — it’s also about understanding execution cost. Every relationship type you choose changes how Dataverse has to retrieve, join, and process your data. Focusing only on how the schema looks without considering how it runs can leave you with a structure that makes perfect sense on paper but feels painfully slow in production. And while streamlining relationships removes a huge chunk of that processing overhead, there’s still another factor that decides how fast Dataverse responds — the indexing strategy driving those queries in the first place.Indexing: The Quiet Performance MultiplierQueries are only as fast as the paths they can take — and in Dataverse, indexing decides that path. Most makers have some awareness that indexes exist, but in practice, it’s one of the least understood parts of performance tuning. You can have a clean table structure and streamlined relationships, but if Dataverse can’t quickly find the records it needs, everything else slows to match the slowest search. Think of it like trying to find a single box in a massive warehouse. Without any indexing, you’re walking aisle to aisle, checking every shelf until you spot the right one. That works when the warehouse is small, but once you scale to millions of items, it becomes ridiculous. Indexing is the equivalent of having a precise map and direct route to the exact shelf. The less work Dataverse has to do to locate a record, the faster every view, filter, and automation runs. Dataverse automatically creates certain indexes for you — primarily on primary keys, lookups, and some system columns. That’s why new environments often perform fine without any manual indexing. But auto-indexing has limits. Complex queries with multiple conditions, especially on custom columns, may end up scanning large parts of the table because there’s no targeted index to guide them. That’s the point where you start to see slow dashboards, report delays, and list views that don’t load smoothly. The other extreme — over-indexing — can be just as bad. Every time you insert, update, or delete a record, Dataverse has to maintain all relevant indexes. Too many custom indexes can increase write times andBecome a supporter of this podcast: https://www.spreaker.com/podcast/m365-show-podcast--6704921/support.Follow us on:LInkedInSubstack
More episodes of the podcast M365 Show Podcast
The M365 Attack Chain Is Not What You Think
02/12/2025
ZARZA We are Zarza, the prestigious firm behind major projects in information technology.