Performance Notes
Understanding RoomSharp's performance optimizations
Core Performance Features
RoomSharp is designed for maximum performance through several key innovations:
1. Zero Reflection
All database operations use source-generated code. No runtime reflection, no IL weaving - just pure, compiled C#.
- Entity mapping generated at compile-time
- DAO implementations fully generated
- No dynamic method invocation
2. IL-Based Mapping (ILFactory)
Version 0.4.0+ introduced high-performance IL code generation:
- Zero boxing for value types
- Direct property setters (no reflection)
- Span-based fast paths for arrays and collections
- Type-safe reading with
ReaderKind
3. Batch Insert Engine
Delivers 2X-5X faster performance for bulk operations:
- Zero allocations in hot loops
- Prepared statement reuse
- Optimized column name arrays (
static readonly ImmutableArray) - Fast paths for different collection types
Benchmark Results
See detailed benchmarks on the Benchmarks page. Key highlights:
| Operation | RoomSharp | Dapper | Improvement |
|---|---|---|---|
| Single Insert | ~0.05ms | ~0.06ms | ~15% faster |
| Single Query | ~0.03ms | ~0.035ms | ~14% faster |
| Batch Insert (1000) | ~18ms | ~35ms | ~48% faster |
| Batch Insert (5000) | ~82ms | ~170ms | ~52% faster |
Memory Efficiency
Minimal Allocations
- Static column name arrays prevent repeated allocations
- Prepared statements reused across operations
- Value types mapped without boxing
- Span-based reading for collections
Auto-Close Connections
C#
var db = RoomDatabase.Builder<AppDatabaseImpl>()
.UseSqlite("app.db")
.SetAutoCloseTimeout(TimeSpan.FromMinutes(5))
.Build();
// Connection auto-closes after 5 minutes idle
// Reopens transparently on next use
Optimization Techniques
1. Use Async Methods
C#
// ❌ Blocks thread
var user = db.UserDao.GetById(123);
// ✅ Async, non-blocking
var user = await db.UserDao.GetByIdAsync(123);
2. Batch Operations
C#
// ❌ Slow: Individual inserts
foreach (var user in users)
db.UserDao.Insert(user);
// ✅ Fast: Batch insert
db.UserDao.InsertAll(users);
3. Use Transactions
C#
// ❌ Multiple disk writes
db.UserDao.Insert(user1);
db.UserDao.Insert(user2);
// ✅ Single transaction, one commit
await db.RunInTransactionAsync(async () => {
await db.UserDao.InsertAsync(user1);
await db.UserDao.InsertAsync(user2);
});
4. Optimize Queries
C#
// ❌ Returns all columns
[Query("SELECT * FROM users WHERE id = :id")]
// ✅ Only needed columns
[Query("SELECT id, name FROM users WHERE id = :id")]
// ✅ Use indexes
[Index(Value = ["email"], Unique = true)]
[Query("SELECT * FROM users WHERE email = :email")]
5. Connection Pooling
For server applications with SQL Server/PostgreSQL/MySQL:
C#
// Connection string with pooling
var db = RoomDatabase.Builder<AppDatabaseImpl>()
.UseSqlServer("Server=...;Min Pool Size=5;Max Pool Size=100;")
.Build();
Performance Improvements by Version
Version 0.4.1 (Latest)
- High-performance BatchInsertEngine (2-5X faster)
- Zero allocations in hot loops
- Prepared statement reuse
- DAO generator routes collections to BatchInsertEngine automatically
Version 0.4.0
- IL-based mappers (no boxing, no allocations)
- Span-driven fast paths
- ReaderKind for typed reads
- Dialect-aware boolean handling
- Normalized column name resolution
Profiling
Custom Query Executor
Implement IQueryExecutor to add profiling:
C#
public class ProfilingQueryExecutor : IQueryExecutor
{
private readonly ILogger _logger;
public ProfilingQueryExecutor(ILogger logger)
{
_logger = logger;
}
public T ExecuteQuery<T>(IDbCommand cmd, Func<IDbCommand, T> handler)
{
var sw = Stopwatch.StartNew();
try
{
return handler(cmd);
}
finally
{
sw.Stop();
_logger.LogInformation(
"Query executed in {ElapsedMs}ms: {CommandText}",
sw.ElapsedMilliseconds,
cmd.CommandText
);
}
}
}
var db = RoomDatabase.Builder<AppDatabaseImpl>()
.UseSqlite("app.db")
.SetQueryExecutor(new ProfilingQueryExecutor(logger))
.Build();
Best Practices Summary
- ✅ Use async methods for all I/O operations
- ✅ Use batch operations for multiple inserts/updates
- ✅ Wrap multiple operations in transactions
- ✅ Add indexes on frequently queried columns
- ✅ Select only needed columns
- ✅ Use connection pooling for server apps
- ✅ Enable WAL mode for SQLite
- ✅ Profile with custom query executor
Next Steps
- Benchmarks - See detailed performance comparisons
- Migrations
- Batch Insert Engine - Learn about bulk operations
- Transactions - Optimize with transactions

