FraiseQL Performance Guide¶
FraiseQL is designed for high performance with PostgreSQL-native optimizations and Rust-powered JSON processing.
Overview¶
FraiseQL achieves exceptional performance through:
- Rust JSON Pipeline: Fast JSON transformation and response building
- PostgreSQL Views: Optimized read-path with materialized views
- Efficient SQL Generation: Smart query planning and execution
- Connection Pooling: Optimal database connection management
- Caching Layer: Optional pg_fraiseql_cache extension
Performance Features¶
1. Rust-Powered JSON Processing¶
FraiseQL uses a Rust extension for JSON operations:
from fraiseql_rs import build_graphql_response, transform_json
# Fast JSON transformation
result = transform_json(data, transform_func)
Performance Benchmarks (fraiseql_rs v0.2.0):
| Test Case | Data Size | Python Time | Rust Time | Speedup |
|---|---|---|---|---|
| Simple (10 fields) | 0.23 KB | 0.055 ms | 0.006 ms | 9.1x |
| Medium (42 fields) | 1.07 KB | 0.122 ms | 0.016 ms | 7.7x |
| Nested (User + 15 posts) | 7.39 KB | 0.915 ms | 0.094 ms | 9.7x |
| Large (100 fields, deep) | 32.51 KB | 2.157 ms | 0.453 ms | 4.8x |
Benefits: - 7-10x faster JSON processing vs pure Python (measured benchmarks) - 2-4x faster end-to-end queries including database time - Zero-copy transformations where possible - Efficient camelCase conversion - Negligible transformation overhead (< 0.1ms for most queries)
2. PostgreSQL View Optimization¶
Read queries use PostgreSQL views for optimal performance:
import fraiseql
@fraiseql.query
def get_users(info: Info) -> list[User]:
# Automatically uses optimized view
return info.context.repo.find("users_view")
Best Practices: - Use views for read operations - Create indexes on frequently queried columns - Use materialized views for expensive aggregations
3. Efficient N+1 Query Prevention¶
FraiseQL includes DataLoader integration:
from fraiseql import dataloader
@field
@dataloader
async def posts(user: User, info: Info) -> list[Post]:
# Automatically batched
return await info.context.repo.find("posts_view", user_id=user.id)
4. Query Complexity Analysis¶
Prevent expensive queries with complexity limits:
from fraiseql import ComplexityConfig
config = ComplexityConfig(
max_complexity=1000,
max_depth=10
)
Performance Benchmarks¶
Latest Results (2025-10-17, fraiseql v0.11.5 with fraiseql_rs v0.2.0):
Transformation Performance¶
- Rust vs Python: 7-10x faster JSON transformation
- End-to-end queries: 2-4x faster including database time
- Transformation overhead: < 0.1ms (negligible)
Typical Query Performance¶
- Simple Query: < 1ms (with Rust pipeline)
- Complex Query with Joins: < 5ms
- Nested relationships: < 10ms (pre-composed in views)
- Mutation: < 10ms
- Bulk Operations: ~1ms per record
APQ + TurboRouter Performance Stack¶
- Base GraphQL: 100ms average response
- + APQ: 20-80ms faster (eliminates parsing)
- + TurboRouter: Additional 2-3x speedup (bypasses GraphQL entirely)
- Total: Up to 6-9x faster for registered queries
See benchmarks/benchmark-results.md for detailed performance tests and reproducibility instructions.
Optimization Tips¶
1. Database Indexes¶
Create indexes for frequently filtered columns:
2. Connection Pooling¶
Configure optimal pool size:
from fraiseql import FraiseQLRepository
repo = FraiseQLRepository(
pool,
pool_size=20, # Adjust based on load
max_overflow=10
)
3. Caching¶
Enable the pg_fraiseql_cache extension:
4. Field Selection¶
Only select needed fields:
5. Pagination¶
Always paginate large result sets:
import fraiseql
@connection
def users(
info: Info,
first: int = 100
) -> Connection[User]:
return info.context.repo.find("users_view", limit=first)
Monitoring¶
Query Performance¶
Monitor query execution time:
Metrics¶
Track key metrics: - Query execution time - Database connection pool utilization - Cache hit rate - GraphQL complexity scores
Troubleshooting¶
Slow Queries¶
- Check EXPLAIN ANALYZE output
- Verify indexes exist
- Review query complexity
- Check connection pool status
High Memory Usage¶
- Reduce result set size with pagination
- Limit query depth
- Review DataLoader batch sizes
- Check for N+1 queries
Database Connection Issues¶
- Review pool configuration
- Check connection timeouts
- Verify max_connections in PostgreSQL
- Monitor connection lifecycle
Advanced Topics¶
Custom Rust Extensions¶
For maximum performance, write custom Rust functions:
use pyo3::prelude::*;
#[pyfunction]
fn custom_transform(data: &PyAny) -> PyResult<String> {
// Your high-performance logic
Ok(result)
}
Query Planning¶
Understand PostgreSQL query plans:
Further Reading¶
- PostgreSQL Performance Tips
- GraphQL Query Complexity
- FraiseQL Benchmarks:
benchmarks/README.md
For questions about performance optimization, open a GitHub discussion.