Service case dashboard slow to load with large volumes of open cases

Our service case dashboard in AEC 2023 has become unusably slow as our case volume has grown. We now have 8,000-10,000 open cases at any given time, and the dashboard takes 30-45 seconds to load. Support agents are frustrated with the wait time, which impacts their ability to triage cases quickly.

The dashboard displays case lists with attachments, comments, and related contact information. It seems like the system is trying to load everything at once rather than using pagination effectively. Query optimization also appears to be an issue - we see multiple database queries executing for related data. Attachment loading is particularly slow when cases have multiple files attached.

We need the dashboard to load in under 5 seconds for our agents to work efficiently. What are the best practices for dashboard pagination, deferred attachment loading, and query optimization?

I’ll provide a complete optimization strategy covering all three critical areas:

Dashboard Pagination Implementation: Replace your current full-load approach with server-side pagination. Configure the dashboard to request only 25 cases per page initially, with the ability to adjust page size to 50 or 100 based on user preference.

Implement cursor-based pagination rather than offset-based for better performance at scale. With offset pagination (LIMIT 1000 OFFSET 5000), the database must scan through 6,000 rows to return page 200. Cursor-based pagination uses the last record’s ID or timestamp to fetch the next page:

SELECT * FROM cases WHERE created_date < ? AND status = ‘open’ ORDER BY created_date DESC LIMIT 25

This query uses an index scan regardless of page depth, maintaining consistent performance.

Add infinite scroll or “Load More” functionality rather than traditional page numbers. This improves perceived performance and matches natural user behavior for case lists.

Implement intelligent prefetching: When a user views page 1, preload page 2 in the background. When they scroll to page 2, page 3 is already loading. This creates the perception of instant navigation while keeping memory usage bounded.

Configure default filtering to show only cases assigned to the current user or their team (typically 50-200 cases) rather than all 10,000 open cases. Provide explicit “View All Cases” option for supervisors who need global visibility. This reduces the default result set by 95%+.

Deferred Attachment Loading Strategy: Eliminate all attachment data from the initial dashboard query. The case list should only load core case fields: ID, subject, status, priority, created_date, assigned_to, customer_name. Display attachment presence with a simple count badge.

Implement three-tier attachment loading:

Tier 1 (Initial load): Show only attachment count from a pre-computed field on the case record. Update this count via trigger when attachments are added/removed, so no file system queries occur during dashboard load.

Tier 2 (Case expansion): When user expands a case row or opens detail panel, load attachment metadata (filename, size, type, upload_date) via separate AJAX call. Still no file content loading.

Tier 3 (Attachment access): Only when user clicks to view or download an attachment, fetch the actual file from blob storage.

This deferred loading pattern reduces initial page load queries from potentially 10,000+ attachment queries to zero.

For cases with many attachments (10+), implement pagination within the attachment list itself. Show first 5 attachments with “Show all (23)” link to expand the full list.

Implement thumbnail caching for image attachments. Generate thumbnails asynchronously after upload and store them in a CDN. When users expand case details, serve cached thumbnails instantly rather than generating on-demand.

Query Optimization Framework: Address the N+1 query problem systematically:

Replace sequential queries with batch loading. If displaying 25 cases, instead of 25 separate queries for contact information, execute one query:

SELECT c.case_id, co.contact_id, co.name, co.email, co.phone

FROM cases c

JOIN contacts co ON c.contact_id = co.contact_id

WHERE c.case_id IN (?, ?, …, ?) – 25 case IDs

This reduces 25 queries to 1.

Implement strategic denormalization for frequently accessed data. Store customer_name directly on the case record rather than requiring a JOIN to contacts table. Update via trigger when contact name changes. This trades slight data redundancy for massive query performance improvement.

Create composite indexes optimized for common dashboard queries:

  • (status, assigned_to, created_date) for “My Open Cases” view
  • (status, priority, created_date) for “High Priority Cases” view
  • (status, team_id, created_date) for “Team Cases” view

Each index supports both filtering and sorting, eliminating full table scans.

Implement query result caching with Redis or similar. Cache dashboard query results for 60 seconds keyed by user_id and filter combination. Most agents refresh their dashboard every few minutes, so serving cached results for subsequent requests within 60 seconds provides instant load time while keeping data fresh enough for support operations.

Use database query plan analysis to identify slow queries. Run EXPLAIN on your dashboard queries to verify they’re using indexes properly. Look for “table scan” or “sort” operations in the plan - these indicate optimization opportunities.

Implement read replicas for dashboard queries. Route all dashboard SELECT queries to a read replica database, reserving the primary database for case updates and writes. This prevents dashboard load from impacting case creation and update performance.

Additional Performance Enhancements: Implement progressive rendering. Load and display the case list grid immediately (2-3 seconds), then progressively enhance with additional data (comment counts, last activity timestamps) as background requests complete. This provides immediate usability while full data loads.

Add dashboard state persistence. Remember user’s filter preferences, sort order, and page position in browser local storage. When they return to the dashboard, restore their previous view state instantly from cache while fresh data loads in background.

Implement real-time updates via WebSocket for new cases or status changes rather than requiring page refresh. This keeps the dashboard current without repeated full queries.

Performance Targets: With these optimizations implemented:

  • Initial dashboard load: 2-4 seconds (down from 30-45s)
  • Page navigation: < 1 second
  • Case detail expansion: < 500ms
  • Attachment list load: < 300ms

Monitor query execution time and set alerts if dashboard queries exceed 1 second. Track user-perceived performance with Real User Monitoring to ensure the optimizations deliver actual improvement in agent productivity.


This draft is based on general Adobe Experience Cloud knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

The 30-45 second load time definitely indicates the dashboard is trying to load all 10,000 cases at once. You need to implement proper pagination with a reasonable page size - 25 or 50 cases per page maximum. Configure lazy loading so only the visible page is fetched from the database. Also enable virtual scrolling if your dashboard framework supports it, which renders only visible rows in the DOM even if more data is loaded.

“Tested this on Adobe Experience Manager with 8,000 open cases — switching to cursor-based pagination dropped dashboard load time from 14 seconds to under 2.”

From a UX perspective, loading 10K cases isn’t just a technical problem - it’s a usability issue. Support agents don’t need to see all cases simultaneously. Implement smart filtering and saved views. Default to showing only cases assigned to the current agent (typically 20-50 cases), with filters to expand to team or all cases when needed. This reduces the default query result set by 99% and makes the dashboard instantly useful.

The multiple database queries for related data is a classic N+1 query problem. Your dashboard is probably loading the case list, then making separate queries for each case’s attachments, comments, and contact info. Use query optimization with JOIN statements or batch loading to fetch all related data in 2-3 queries instead of thousands. Implement eager loading for relationships that are always displayed and lazy loading for data that’s only shown on expansion or drill-down.

Attachment loading is killing your performance because you’re probably loading actual file metadata or even thumbnails for all attachments upfront. Implement deferred loading where attachment information is only fetched when a user expands a case detail view. Show just an attachment count badge on the case row initially, then load the attachment list on-demand. This eliminates hundreds of unnecessary file system or blob storage queries on initial page load.

Your case query needs proper indexing and sorting optimization. If agents typically sort by creation date or priority, ensure you have composite indexes on (status, created_date) and (status, priority, created_date). Without proper indexes, sorting 10K records requires a full table scan and in-memory sort, which is extremely slow. Also implement query result caching with a short TTL (30-60 seconds) for common dashboard views.

Consider implementing a dashboard data aggregation layer. Instead of querying the live case table directly, create a materialized view or summary table that’s updated every 2-3 minutes with case counts, priority distribution, and other dashboard metrics. The dashboard queries this fast summary table first to show overview statistics, then only queries detailed case data for the specific page being viewed. This hybrid approach gives instant dashboard load with fresh enough data for support operations.