Bulk Insert - Complex Objects
Example: Bulk insert of complex employee records.
Classic ORM (EF Core) would require ~28 tables:
For 100 employees: 4000-6000 INSERTs!
REDB: 2 tables (_objects + _values), ~3000 records, single BulkInsert via COPY.
Classic ORM (EF Core) would require ~28 tables:
- Employees - main table
- EmployeeSkills - string[] Skills (FK)
- EmployeeSkillLevels - int[] SkillLevels (FK)
- EmployeeCertifications - string[] (FK)
- EmployeeCertificationYears - int[] (FK)
- Addresses - for Home/Work/Emergency (FK)
- BuildingInfos - nested in Address (FK)
- BuildingAmenities - string[] in BuildingInfo (FK)
- BuildingAccessCodes - int[] in BuildingInfo (FK)
- BuildingParkingSpots - string[] (FK)
- BuildingElevatorFloors - int[] (FK)
- Contacts - Contact[] (FK)
- ContactNotificationHours - int[] in Contact (FK)
- ContactMetadata - ContactDetail[] in Contact (FK)
- ProjectMetrics - RedbObject reference
- ProjectTags - Tag[] in ProjectMetrics (FK)
- ProjectTechnologies - string[] in ProjectMetrics (FK)
- EmployeePastProjects - many-to-many (2 FK)
- PhoneDirectory - Dictionary (FK)
- OfficeLocations - Dictionary + Address (2 FK)
- BonusByYear - Dictionary (FK)
- DepartmentHistory - Dictionary (FK)
- Departments - nested class
- DepartmentProjects - string[] (FK)
- DepartmentLeaders - Tag[] (FK)
- DepartmentBudgetByYear - nested Dictionary (FK)
- PerformanceReviews - tuple key Dictionary (FK)
- ProjectMetricsDict - Dictionary with RedbObject (2 FK)
For 100 employees: 4000-6000 INSERTs!
REDB: 2 tables (_objects + _values), ~3000 records, single BulkInsert via COPY.
var sw = Stopwatch.StartNew();
const int count = 100;
var employees = CreateEmployees(count);
// Bulk insert using COPY protocol (Pro feature)
var savedIds = await redb.SaveAsync(employees);
sw.Stop();
// Classic ORM: ~25 tables, ~5000 INSERTs with FK ordering
// REDB: 2 tables, ~3000 values, single BulkInsert
GetSkillsForPosition
private static string[] GetSkillsForPosition(string position, int index)
{
var skills = position switch
{
"Developer" => new[] { "C#", "SQL", "Azure", "Docker" },
"Designer" => new[] { "Figma", "Photoshop", "CSS" },
"Analyst" => new[] { "SQL", "Excel", "Python" },
"Manager" => new[] { "Leadership", "Agile", "Communication" },
_ => new[] { "Communication", "Teamwork" }
};
var take = position == "Developer" ? 2 + index % 3 : 2 + index % 2;
return skills.Take(Math.Min(take, skills.Length)).ToArray();
}
MS Pro
1202ms(100)
postgres.ef
1708ms(100)
PG Pro
1069ms(100)
sqlite.pro
1891ms(100)