Performance
In production, a critical executive dashboard report is timing out consistently during peak hours (8-10 AM).
The question
Why This Comes Up in Interviews
A complex report timing out in production typically stems from inefficient database queries scanning massive datasets without proper indexing, combined with peak-hour resource contention. With 500K+ incident records over 90 days, the pivot aggregation by CI, Priority, and State triggers full table scans, Cartesian products from unoptimized joins, and heavy CPU for MTTR calculations—all exacerbated by dashboard multi-threading limits and reporting node saturation.
Diagnosis Approach (Senior Expectation): Don't jump to code fixes. First, reproduce in sub-prod with similar data volume. Check System Logs & Transaction Logs for query plans (enable SQL trace). Use System Diagnostics > Slow Queries to identify the culprit. Monitor Node CPU/Memory via Stats.do and DB execution plans via JDBC probes. Validate indexes on incident.sys_created_on, cmdb_ci, priority, state. Great answers quantify: "Query scans 2M rows, 80% CPU spike, no CI index hit."
The Solution
Problem: Inefficient Scripted Filter (causes full scan)
var problematicFilter = function() {
var gr = new GlideRecord('incident');
gr.addQuery('sys_created_on', 'STARTSWITH', gs.beginningOfLast90Days());
gr.addJoinQuery('cmdb_ci', 'cmdb_ci', 'sys_id', 'cmdb_ci');
gr.addAggregate('COUNT', 'number');
gr.addAggregate('AVG', 'business_duration');
gr.query(); // Scans ALL records, no indexes, pivot explodes
while(gr.next()) { /* heavy processing */ }
return 'sys_idIN' + getAllSysIds(gr);
};Solution: Optimized Scripted Filter with Indexing & Limits
var optimizedFilter = function() {
var gr = new GlideRecord('incident');
gr.addQuery('sys_created_on', '>=', gs.beginningOfLast90Days());
gr.addQuery('assignment_group', 'IN', groupSysIds.join(','));
gr.orderBy('sys_created_on');
gr.setLimit(500000); // Prevent OOM
gr.query(); // Leverages compound index
var ciMap = {};
while(gr.next()) {
var ci = gr.getValue('cmdb_ci');
ciMap[ci] = (ciMap[ci] || 0) + 1;
}
return 'sys_idIN' + Object.keys(ciMap).join(',');
};Senior Considerations
- Three Solution Options w/ Trade-offs: 1) Quick Fix - Add Indexes & Row Limits: Index
incident.sys_created_on,assignment_group,cmdb_ci(fastest ROI, but doesn't scale beyond 1M rows). 2) Mid-term - Scheduled Reports + PA Indicators: Offload to Performance Analytics with breakdowns (reduces live load 90%, but 15-min latency vs. real-time). 3) Strategic - Data Warehouse Export: Nightly ETL to external BI (scales infinitely, but $cost + data staleness). - Production Rollout: Test in DEV & PERF with 110% data volume. Stagger: Indexes first (no downtime), then report config. Use Update Sets for scripted filters. Monitor with APM/Splunk for 48hrs post-deploy.
- Great Answer Separators: Quantifies impact ("reduces query time 85% via index hit ratio"), discusses edge cases (holiday data spikes, null CI handling), failure modes (index fragmentation), and holistic metrics: Report load time <30s, Node CPU <70%, User abandonment rate=0%.
- Why This Matters: Good candidates fix syntax. Seniors prevent recurrence via root cause (missing indexes on high-cardinality fields) and balance user experience with platform stability.