Q:

CPU time limit exception on xml class

My class below is timing out with the 'System.LimitException: Apex CPU time limit exceeded' exception. We have an external app that taps into our org retrieve account data (parent, child) and from a related child object (Group_Plans__r).
What sections of my code would you suggest I refactor to reduce the cpu execution time while preserving the xml structure?
global class DomXmlGenerator {       

    webservice static String getXml() {
        Dom.Document doc = new Dom.Document();

        Dom.Xmlnode rootNode = doc.createRootElement('response', null, null);

        List<Account> accountList = new List<Account>([SELECT Id, ParentId, Ultimate_Parent_Account_Id__c, Name, Ultimate_Parent_Id__c, Account_Id__c, CARRIER_S_ID__c, Ultimate_Parent__c, Carrier_Account_Id__c, Carriers_Name__c, Carrier__c, SafeName__c, Safe_Id__c, (SELECT Id, Name, Group_ID__c, Group_Effective_Date__c FROM Group_Plans__r) FROM Account WHERE Inactive__c = False ORDER BY Name]);

        for(Account a : accountList) {

            Dom.XMLNode ultimateParentNode = rootNode.addChildElement('UltimateParent', null, null);
            String idString = a.Ultimate_Parent_Id__c;
            Id idVal = idString;
            ultimateParentNode.setAttribute('Id', idVal);
            ultimateParentNode.setAttribute('Name', a.Ultimate_Parent__c);
            if (String.IsNotBlank(a.Ultimate_Parent_Account_Id__c)) {
                ultimateParentNode.setAttribute('Account Id', a.Ultimate_Parent_Account_Id__c);
            }
            Dom.XMLNode carrierNode = ultimateParentNode.addChildElement('Carrier', null, null);
            if (String.isNotBlank(a.Carrier__c)) {
                carrierNode.setAttribute('Id', a.Carrier__c);
                carrierNode.setAttribute('Name', a.Carriers_Name__c);
            }
            if (String.IsNotBlank(a.CARRIER_S_ID__c)) {
                carrierNode.setAttribute('CarrierId', a.CARRIER_S_ID__c);
            }
            Dom.XmlNode accountNodes = carrierNode.addChildElement('Account', null, null);
            accountNodes.setAttribute('Id', a.Id);
            accountNodes.setAttribute('Name', a.Name);
            if (String.IsNotBlank(a.Account_ID__c)) {
                accountNodes.setAttribute('AccountId', a.Account_ID__c);
            }
            for(Group_Name__c g : a.Group_Plans__r) {
                Dom.XmlNode groupNode = accountNodes.addChildElement('Group', null, null);
                if (String.IsNotBlank(g.Group_ID__c)) {
                    groupNode.setAttribute('GroupId', g.Group_Id__c);
                }
                if (String.IsNotBlank(g.Name)) {
                    groupNode.setAttribute('Name', g.Name);
                }
                if (String.IsNotBlank(String.valueOf(g.Group_Effective_Date__c))) {
                    groupNode.setAttribute('EffectiveDate', String.valueOf(g.Group_Effective_Date__c));
                }

            }

        }        
        //System.debug(doc.toXmlString());
        return doc.toXmlString();
    }
}

A:

Looking at your query, you appear to be returning every Account in the org and every child Group_Plan__c of each of those. As Salesforce has hard limits on CPU time, number of rows, size of response etc that approach is not going to work if the number of Account and Group_Plan__c records grows as presumably it will.
Breaking the return of the data up into separate responses (and making multiple requests) is generally the way to go. If there is any natural division of the data, supply a parameter that specifies that and use it in the query. Or you can implement a pagination approach "give me 100 Accounts starting at offset 700". Or you might supply a date/time window and only return records with LastModifiedDate in that window so your external app just gets changes (though that would miss deletes).

