I need to write a Batch class to delete records from Child to Parents objects:

Child__c --> Parent__c --> Parent_Of_Parent__c

Every object has approximately 5 million records to delete, so I want to make sure I don't hit Salesforce limits. The query in the start method has a semi-join:

Select id, Date__c, Parent__c from Child__c where Date __c < LAST_N_Days:365 and Id not in (SELECT Child__c from OtherObject)

I know that with QueryLocator I can retrieve 50 million records, but I don’t know if with semi-joins I’ll get Query Timeout Error (‘OtherObject’ has 1.5 million records). Also, I don’t know if I’ll hit any Governor Limit with the semi-join.

I found this answer about semi-joins: What are the limitations on using a semi-join in a batch apex query locator? but in the Developer Console it doesn't seem like semi-joins are being counted. Or am I wrong?

If it can help, this is my code (any suggestion is welcome):

Batch Class

global class BatchWorkaround implements Database.Batchable<sObject>{

    global Database.QueryLocator start(Database.BatchableContext BC){

        String query = 'Select id, Date__c, Parent__c from Child__c where Date __c < LAST_N_Days:365 and Id not in  (SELECT Child__c from OtherObject)';
        return Database.getQueryLocator(query);

    global void execute(Database.BatchableContext BC, List<sObject> scope){

        DeleteOtherRecords.execute((List<Child__c>) scope);
        delete scope;
    global void finish(Database.BatchableContext BC) {
    //do something


DeleteOtherRecords Class

public class DeleteOtherRecords{
    private static List<Parent__c> cp = new List<Parent__c>();
    private static List<Parent_of_Parent __c> op = new List<Parent_of_Parent __c>();
    private static List<Parent_of_Parent __c> noOthers = new List<Parent_of_Parent __c>();
    public static void execute(List<Child__c> scope){
        List<Id> cList = new List<Id>();
            for(Child__c c: scope){
            cp = [SELECT ID, Parent_of_Parent__c FROM Parent__c WHERE ID IN : cList];
        List<Id> opList = new List<Id>();
            for(Parent__c a: cp){
            op = [SELECT ID FROM Parent_of_Parent__c WHERE ID IN : opList];     
        if(cp.size() > 0){
            delete cp;

        if(op.size() > 0){
            noOthers = [SELECT ID FROM Parent_of_Parent__c WHERE ID IN: op AND ID NOT IN (SELECT Parent_of_Parent__c FROM Parent__c)];
            if(noOthers.size() > 0){                   
            delete noOthers;


You must log in to answer this question.

Browse other questions tagged .