Technical Analysis: OMGT Search & Export Performance
1. Problem Statementβ
The OMGT Advanced Search and Data Export functionalities suffer from severe performance degradation, frequently leading to HTTP 500 errors (timeouts) and high server resource consumption. This prevents users from effectively filtering large order volumes and generating requisite reports.
Related Documents:
- π£οΈ Debate: Analysis_Debate.md
- π UX Analytics: Search_Usage_Analytics.md
- πΊοΈ Action Plan: Action_Plan.md
- π Functional Specs: AdvancedSearch.feature | Mapping
2. Identified Anti-Patternsβ
A. Sub-optimal Client-Side Evaluation (Search)β
Location: OrderAdvancedSearchQueryBuilder.FinaliseQuery
Pattern:
foreach (EITInterval zipRange in this.listPostCodeRange) {
ordersQueryTemp.AddRange(ordersQuery.Where(c => ...));
}
ordersQuery = ordersQueryTemp.AsQueryable().Distinct();
- Issue: Instead of generating a single SQL
INorBETWEENsequence, the code executes a separate database query for each postcode range. - Impact: Multiplies database round-trips and forces the final result set into memory (
ordersQueryTemp), breaking database-side paging and sorting.
B. Redundant Data Orchestration (Search)β
Location: OrderAdvancedSearchQueryBuilder.BuildQuery
Pattern: Manual .Join() calls for tables already present in the source view (OrderTravelProductSearchViewList).
- Issue: The query builder re-implements joins that are already defined in the SQL View level.
- Impact: Increases SQL complexity (nested joins), leading to sub-optimal execution plans by the SQL Server optimizer.
C. Row-Based Template Resolution (Export)β
Location: MassActionHandler.ExportExcel calling HandleResolverTemplateExport
Pattern:
foreach (OrderTravelProductOMGT otp in selectedOrderTravelProduct) {
// Re-initializes EITTextTemplate and all resolvers for EVERY row
List<EITEntityTTResolver> resolvers = this.OnRaiseWepMassActionExportEvent(...);
rows = this.HandleResolverTemplateExport(rows, ...);
}
- Issue: The system treats every export row as a unique "document" requiring its own template resolution engine instance.
- Impact: CPU-bound bottleneck. For 1,000 rows, it performs 1,000+ reflection-heavy resolutions, even if the patterns are static or simple property access.
D. "God Class" Complexityβ
Location: OrderAdvancedSearchQueryBuilder.cs (5,763 LOC)
- Metrics:
- ~30 distinct filter categories (Global, Accounting, School, Travel, etc.).
- ~1,227 LOC in the input DTO (
SearchOrderOMGTDto). - Combinatorial Explosion: Users can combine any subset of these 30 categories, leading to an effectively infinite number of possible query plans.
- Issue: Excessive chaining of conditional LINQ filters in a single class.
- Impact: Difficult to maintain, test, or optimize. The SQL logic for one category (e.g., "Flights") often implicitly depends on joins added by another category (e.g., "Invoice"), creating fragile dependencies.
3. Mitigation Expectationsβ
| Problem Area | Mitigation Strategy | Expected Result |
|---|---|---|
| Search (Postcodes) | Convert foreach loop into a combined LINQ predicate (e.g., .Where(c => ranges.Any(...))). | Reduction from N queries to 1 single query. Restoration of DB-level paging. |
| Search (Joins) | Audit and remove Join calls for fields already in the View. | Cleaner SQL, reduced join depth, faster execution plan generation. |
| Export (Latency) | Data Prefetching: Parse template to identify and batch-load relationships (eliminated N+1). | Elimination of thousands of DB roundtrips. CPU latency becomes negligible once I/O is fixed. |
| Export (Legacy) | Maintain EITTextTemplate engine but feed it pre-hydrated in-memory entities. | 100% backward compatibility with custom patterns while achieving performance gains. |
4. Risks & Constraintsβ
- Functional Parity: Any change to
Distinct()logic must be verified to ensure no duplicated rows appear in the search results. - Template Compatibility: Legacy custom export patterns rely on the existing resolver chain. A "Fast Path" must safely fallback to the template engine for unrecognized patterns.