The real-world impact of Salesforce Data Skew
If you’ve ever dealt with a batch job that suddenly crawls to a halt or seen those annoying “UNABLE_TO_LOCK_ROW” errors popping up in your logs, you might be dealing with Salesforce Data Skew. It is one of those things that doesn’t really show up in a fresh sandbox with a few hundred records, but it will absolutely wreck your performance once you hit production scale. I’ve seen teams spend weeks chasing ghost bugs only to realize they just had a massive imbalance in how their records were distributed.
Basically, Salesforce Data Skew happens when your data isn’t spread out evenly. When you have too many records tied to a single owner, a single parent record, or even a single picklist value, you create “hotspots” in the database. These hotspots lead to locking issues and slow queries because the system is working overtime to manage the relationships or sharing rules for that one specific point.
Ownership Skew
This is probably the most common one I run into. It happens when a single user or a queue owns more than 10,000 records of a specific object. I once worked on a project where a “placeholder” user owned nearly 500,000 leads. Every time we tried to update the role hierarchy or change a sharing rule, the system would time out because it had to recalculate sharing for half a million records just for that one guy. It’s a nightmare for performance.
Lookup Skew
Lookup skew is what happens when a huge number of child records all point to the same parent record. Think about a “Generic Account” that everyone uses to link contacts that don’t have a real company yet. If that one account has 50,000 contacts, any update to one of those contacts might try to lock the parent account. If you’re running a bulk update, you’ll hit those row lock errors almost immediately.

Why Salesforce Data Skew ruins your day
So why does this matter? Aside from the obvious “it’s slow,” the technical debt is real. When you have skewed data, your sharing recalculations take forever. Salesforce uses a complex engine to figure out who can see what, and when you bunch everything up under one owner or parent, that engine has to do way more work than it should. This is a huge part of managing Salesforce large data volumes effectively.
You’ll also run into issues with list views and reports. If you’re filtering by an owner who has 100,000 records, the database index might not even be selective enough to help. The query optimizer just gives up and does a full table scan, and then your users start complaining that their “My Leads” view is taking 30 seconds to load. Sound familiar?
“The biggest mistake I see is developers assuming that a ‘placeholder’ record is a safe way to handle unassigned data. It’s actually a performance time bomb.”
How to find and fix Salesforce Data Skew
The first step is actually knowing you have a problem. You can’t just guess. I usually start with some simple SOQL queries to see where the concentrations are. If you suspect ownership skew, run something like this:
SELECT OwnerId, COUNT(Id)
FROM Account
GROUP BY OwnerId
HAVING COUNT(Id) > 10000If that query returns any rows, you’ve got work to do. Now, fixing it isn’t always easy, but here is what actually works in the field:
- Spread the love: Don’t let one user own everything. Use a round-robin approach or multiple queues to distribute the load.
- Sharding parent records: If you have lookup skew, create multiple “dummy” parents instead of just one. If you need a generic account, create “Generic Account 1”, “Generic Account 2”, and so on.
- Go async: Use asynchronous Apex to handle updates. It doesn’t fix the skew, but it handles the retries and locking better than a synchronous process would.
- Watch your batch sizes: If you’re hitting locks, drop your batch size down to 50 or even 20. It’s slower, but it’s better than failing entirely.
A quick Apex tip for locking
One trick I’ve used is to sort my records by OwnerId before doing a DML operation. If you group your updates so that all records for “Owner A” are processed together, you reduce the chance of different threads fighting over the same parent lock at the same time. Here is a basic way to think about it:
// Grouping by owner to minimize lock contention
Map<Id, List<Account>> accountsByOwner = new Map<Id, List<Account>>();
for (Account acc : triggerNew) {
if (!accountsByOwner.containsKey(acc.OwnerId)) {
accountsByOwner.put(acc.OwnerId, new List<Account>());
}
accountsByOwner.get(acc.OwnerId).add(acc);
}By processing these groups, you’re being much kinder to the database. It’s also worth checking out Salesforce Flow bulkification if you’re seeing these issues in your declarative automation, as Flows can be notorious for hitting these limits if not built carefully.
Key Takeaways
- Salesforce Data Skew is caused by an uneven distribution of records (Ownership, Lookup, or Picklist).
- The “magic number” where things usually start breaking is 10,000 child records per parent or owner.
- Row locking errors (UNABLE_TO_LOCK_ROW) are the most common symptom of a skew problem.
- Fixing it usually requires architectural changes like record sharding or better ownership distribution.
- Always test with realistic data volumes in a sandbox before deploying major changes to a large org.
Wrapping it up
At the end of the day, Salesforce Data Skew is just a part of growing a large org. It’s not a sign of a “bad” system, but it is a sign that your data model needs to evolve. Don’t wait until your users can’t save records to start looking into this. Run those GROUP BY queries today and see what’s actually going on under the hood. It’ll save you a lot of late-night debugging later on.








Leave a Reply