Posted on Feb 27, 2017

Salesforce gave us Partial Copy Sandboxes (which I think have been renamed Partial Data Sandboxes) and Sandbox Templates a few releases ago, the former of which is sort've halfway between a Developer Pro sandbox and a Full sandbox, where it doesn't have all your data and can be refreshed more quickly than a full sandbox, and the latter is used to specify the data you want to copy from prod when refreshing a Full or Partial Copy Sandbox.

I wanted to write about some weirdness with Partial Copy Sandboxes.

Partial Copy Sandboxes have some limits, which (as of this posting) are namely a 5 GB total database space limit, and a 10,000 record limit per object.

If the object you're sending off to your Partial Copy Sandbox has more than 10K records, Salesforce selects records at random to include in the copying process, up to the limit of 10K.  For records with a master-detail relationship or a lookup field that is marked as required, the children and parent records are included together....

Sorta.  That 10K limit can make things a bit weird.  Children records in a master-detail relationship or a required lookup relationship have to have a parent, so Salesforce will export the child records up to the 10K and limit and then they'll stop.  This can mean that you could end up with childless parent records in your partial sandbox.

Salesforce talks about this in this knowledge article.

One thing Salesforce doesn't mention is what happens to normal lookup relationship fields when records hit the 10K limit:  They become "ghosts".

"Child" records in the lookup relationship will end up with some references to their "ghost" parents, their field will have a value, the SF id of the record it looks to, but the source record doesn't exist.  This can result in wonky code, test classes and SOQL behaviour. The field isn't null, but there's nothing on the other end of that reference. In SOQL, this means you could have "SELECT My_Lookup__c, My_Lookup__r.Name FROM Whatever__c" and My_Lookup__c will have a value, but My_Lookup__r.Name will be null.

If you're going to be using partial sandboxes on a regular basis in your project, then definitely keep this in mind when you're writing trigger code and test classes: basically null check everything :P

Bonus: Vote up this idea around making sure partial sandboxes maintain referential integrity.