ブログ
すべてのブログ記事Optimising Portfolio Initialisation: Achieving ~99.96% Reduction in Processing Time
Alexander Talei
Founder at Obermind
$ ./portfolio-init --mode=bulk --users=164,284
[2024-01-15 06:08:19.123456] ObermindStream - Starting portfolio initialisation...
[2024-01-15 06:08:19.143902] Loading user data... ✓
[2024-01-15 06:08:19.167210] Initialising strategies...
✓ Successfully initialised 164284 portfolios
Performance gain: 99.96%
Database calls optimised: Millions → 1
Scalability: Linear performance scaling
The Challenge
In financial technology, performance isn't just about user experience — it's about operational efficiency at scale. Our trading platform serves over 150,000+ active portfolios globally, and during system startup we need to initialise portfolio strategies for all users to ensure they're ready for market operations. That includes running valuations and risk metrics, loading orders, constructing positions, handling instrument and market data subscriptions, and more.
What started as a minor inconvenience with a few hundred users had grown into a significant operational bottleneck. Our initialisation process was taking over ~5.06 seconds on average per portfolio, and we knew this would scale poorly as our user base continued to grow.
The Problem: Death by a Million Database Calls
Our original initialisation approach seemed logical at first glance:
For each user portfolio:
1. Simulate login authentication
2. Initialise portfolio strategy
3. Set up market data subscriptions
4. Simulate logoutHowever, this approach had a fatal flaw hidden in the authentication step. Each simulated login was performing multiple database queries:
- Credential verification — database query to validate user credentials
- User data retrieval — database query to fetch user account information
- Account validation — additional queries for account status checks
On a development server with only 484 portfolios, this resulted in 1,500+ individual database calls during startup. On our globally distributed production infrastructure — with databases across numerous datacenter locations — network latency amplified this into an unacceptable initialisation time.
The Investigation
Performance profiling revealed the bottleneck wasn't in the portfolio logic itself (which we'd spent years fine-tuning for ultra low-latency operations), but in the authentication layer that was silently creating unnecessary database calls. Each user initialisation was waiting for database roundtrips that were completely unnecessary — we already knew these were valid users since we'd just queried them from the database.
The authentication calls were happening because we were simulating the full login/logout cycle to trigger the portfolio initialisation code paths. While this ensured consistency with the normal user flow, it created a massive performance penalty during bulk initialisation.
The Solution: Direct Portfolio Initialisation
We implemented a direct initialisation approach that bypasses unnecessary authentication while maintaining all the critical portfolio setup logic.
Before (slow path):
Single DB query: Get all users
For each user:
├── Simulate login → Database credential check
├── Simulate login → Database user data fetch
├── Initialise portfolio strategy ✓
├── Setup market subscriptions ✓
└── Simulate logout → Database cleanupAfter (fast path):
Single DB query: Get all users
For each user:
├── Create portfolio context directly
├── Initialise portfolio strategy ✓
├── Setup market subscriptions ✓
└── Clean up resourcesThe key insight was that portfolio initialisation and user authentication are orthogonal concerns. During startup, we don't need to verify credentials — we need to ensure portfolios are ready for trading and operations involving their assets.
Implementation Strategy
- Preserved original logic — we kept the existing initialisation method intact for individual user scenarios
- Added direct path — created a new initialisation method specifically for bulk operations
- Maintained consistency — all the same portfolio setup, market data subscriptions, and business logic still execute
- Zero behavioural changes — the end result is identical; only the path to get there is optimised
The Results
The performance improvement was dramatic:
| Metric | Before | After | | --- | --- | --- | | Time per portfolio | ~5.06 seconds | ~1.73 milliseconds | | Improvement | — | ~99.96% reduction | | Database calls (production) | Hundreds of thousands | 1 | | Scalability | Exponential degradation | Linear scaling |
$ ./portfolio-init --mode=bulk --users=164,284
For our production environment serving 150,000+ portfolios, this optimisation means:
- Startup time reduced dramatically
- Significantly reduced database load during deployments
- Faster disaster recovery and system restarts
- Improved operational efficiency
Key Lessons Learned
-
Profile before optimising — the bottleneck wasn't where we initially suspected. Performance profiling revealed that business logic was fast; it was the authentication layer causing delays.
-
Question every database call — each database query should serve a purpose. During bulk operations, many individual queries can often be replaced with a single batch operation.
-
Separate concerns — authentication and initialisation are different concerns. During startup, we don't need to verify what we already know to be true.
-
Preserve existing behaviour — optimisation shouldn't change functionality. We maintained the original code path for individual operations while adding an optimised path for bulk operations.
-
Think about scale early — what works for 100 users might not work for 100,000. Consider how your initialisation patterns will scale with growth.
Technical Implementation Notes
The solution involved:
- Smart batching — single query to fetch all user data upfront
- Direct object creation — bypassing authentication layers during bulk initialisation
- Resource management — proper cleanup of temporary objects
- Progress monitoring — added progress indicators for operational visibility
- Graceful degradation — fallback to original method when needed
Conclusion
This optimisation demonstrates that significant performance gains often come from questioning fundamental assumptions about how systems should work. By separating authentication concerns from portfolio initialisation, we achieved a nearly 3000× performance improvement.
The lesson extends beyond our specific use case: when building systems at scale, always consider whether your initialisation patterns will grow linearly or exponentially with your user base. Sometimes the best optimisation is not doing unnecessary work at all.