Skip to content

Latest commit

 

History

History
666 lines (560 loc) · 31 KB

File metadata and controls

666 lines (560 loc) · 31 KB

EntityFrameworkCore.SqlServer.SimpleBulks

A very simple .net core library that can help to sync a large number of records in-memory into the database using the SqlBulkCopy class.  

Overview

This library provides extension methods so that you can use with your EntityFrameworkCore DbContext instance DbContextExtensions.cs or you can use SqlConnectionExtensions.cs to work directly with a SqlConnection instance without using EntityFrameworkCore.

Nuget

https://www.nuget.org/packages/EntityFrameworkCore.SqlServer.SimpleBulks

Features

  • Bulk Insert
  • Bulk Update
  • Bulk Delete
  • Bulk Merge
  • Bulk Match
  • Temp Table
  • Direct Insert
  • Direct Update
  • Direct Delete

Examples

EntityFrameworkCore.SqlServer.SimpleBulks.Demo

  • Update the connection string:
    private const string _connectionString = "Server=.;Database=SimpleBulks;User Id=xxx;Password=xxx";
  • Build and run.

DbContextExtensions

Using Lambda Expression

using EntityFrameworkCore.SqlServer.SimpleBulks.BulkDelete;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkInsert;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkMerge;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkUpdate;

// Insert all columns
dbct.BulkInsert(rows);
dbct.BulkInsert(compositeKeyRows);

// Insert selected columns only
dbct.BulkInsert(rows,
    row => new { row.Column1, row.Column2, row.Column3 });
dbct.BulkInsert(compositeKeyRows,
    row => new { row.Id1, row.Id2, row.Column1, row.Column2, row.Column3 });

dbct.BulkUpdate(rows,
    row => new { row.Column3, row.Column2 });
dbct.BulkUpdate(compositeKeyRows,
    row => new { row.Column3, row.Column2 });

dbct.BulkMerge(rows,
    row => row.Id,
    row => new { row.Column1, row.Column2 },
    row => new { row.Column1, row.Column2, row.Column3 });
dbct.BulkMerge(compositeKeyRows,
    row => new { row.Id1, row.Id2 },
    row => new { row.Column1, row.Column2, row.Column3 },
    row => new { row.Id1, row.Id2, row.Column1, row.Column2, row.Column3 });
                        
dbct.BulkDelete(rows);
dbct.BulkDelete(compositeKeyRows);

Using Dynamic String

using EntityFrameworkCore.SqlServer.SimpleBulks.BulkDelete;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkInsert;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkMerge;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkUpdate;

dbct.BulkUpdate(rows,
    [ "Column3", "Column2" ]);
dbct.BulkUpdate(compositeKeyRows,
    [ "Column3", "Column2" ]);

dbct.BulkMerge(rows,
    "Id",
    [ "Column1", "Column2" ],
    [ "Column1", "Column2", "Column3" ]);
dbct.BulkMerge(compositeKeyRows,
    [ "Id1", "Id2" ],
    [ "Column1", "Column2", "Column3" ],
    [ "Id1", "Id2", "Column1", "Column2", "Column3" ]);

Using Builder Approach in case you need to mix both Dynamic & Lambda Expression

new BulkInsertBuilder<Row>(dbct.GetSqlConnection())
	.WithColumns(row => new { row.Column1, row.Column2, row.Column3 })
	// or .WithColumns([ "Column1", "Column2", "Column3" ])
	.WithOutputId(row => row.Id)
	// or .WithOutputId("Id")
	.ToTable(dbct.GetTableName(typeof(Row)))
	// or .ToTable("Rows")
	.Execute(rows);

SqlConnectionExtensions

Using Lambda Expression

using EntityFrameworkCore.SqlServer.SimpleBulks.BulkDelete;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkInsert;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkMerge;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkUpdate;

// Register Type - Table Name globaly
TableMapper.Register(typeof(Row), "Rows");
TableMapper.Register(typeof(CompositeKeyRow), "CompositeKeyRows");

connection.BulkInsert(rows,
           row => new { row.Column1, row.Column2, row.Column3 });
connection.BulkInsert(compositeKeyRows,
           row => new { row.Id1, row.Id2, row.Column1, row.Column2, row.Column3 });

connection.BulkUpdate(rows,
           row => row.Id,
           row => new { row.Column3, row.Column2 });
connection.BulkUpdate(compositeKeyRows,
           row => new { row.Id1, row.Id2 },
           row => new { row.Column3, row.Column2 });

connection.BulkMerge(rows,
           row => row.Id,
           row => new { row.Column1, row.Column2 },
           row => new { row.Column1, row.Column2, row.Column3 });
connection.BulkMerge(compositeKeyRows,
           row => new { row.Id1, row.Id2 },
           row => new { row.Column1, row.Column2, row.Column3 },
           row => new { row.Id1, row.Id2, row.Column1, row.Column2, row.Column3 });
                        
connection.BulkDelete(rows, row => row.Id);
connection.BulkDelete(compositeKeyRows, row => new { row.Id1, row.Id2 });

Using Dynamic String

using EntityFrameworkCore.SqlServer.SimpleBulks.BulkDelete;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkInsert;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkMerge;
using EntityFrameworkCore.SqlServer.SimpleBulks.BulkUpdate;

connection.BulkInsert(rows, "Rows",
           [ "Column1", "Column2", "Column3" ]);
connection.BulkInsert(rows.Take(1000), "Rows",
           typeof(Row).GetDbColumnNames("Id"));
connection.BulkInsert(compositeKeyRows, "CompositeKeyRows",
           [ "Id1", "Id2", "Column1", "Column2", "Column3" ]);

connection.BulkUpdate(rows, "Rows",
           "Id",
           [ "Column3", "Column2" ]);
connection.BulkUpdate(compositeKeyRows, "CompositeKeyRows",
           [ "Id1", "Id2" ],
           [ "Column3", "Column2" ]);

connection.BulkMerge(rows, "Rows",
           "Id",
           [ "Column1", "Column2" ],
           [ "Column1", "Column2", "Column3" ]);
connection.BulkMerge(compositeKeyRows, "CompositeKeyRows",
           [ "Id1", "Id2" ],
           [ "Column1", "Column2", "Column3" ],
           [ "Id1", "Id2", "Column1", "Column2", "Column3" ]);

connection.BulkDelete(rows, "Rows", "Id");
connection.BulkDelete(compositeKeyRows, "CompositeKeyRows", [ "Id1", "Id2" ]);

Using Builder Approach in case you need to mix both Dynamic & Lambda Expression

new BulkInsertBuilder<Row>(connection)
	.WithColumns(row => new { row.Column1, row.Column2, row.Column3 })
	// or .WithColumns([ "Column1", "Column2", "Column3" ])
	.WithOutputId(row => row.Id)
	// or .WithOutputId("Id")
	.ToTable("Rows")
	.Execute(rows);

Configuration

BulkInsert

_context.BulkInsert(rows,
    row => new { row.Column1, row.Column2, row.Column3 },
    options =>
    {
        options.KeepIdentity = false;
        options.BatchSize = 0;
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

BulkUpdate

_context.BulkUpdate(rows,
    row => new { row.Column3, row.Column2 },
    options =>
    {
        options.BatchSize = 0;
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

BulkDelete

_context.BulkDelete(rows,
    options =>
    {
        options.BatchSize = 0;
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

BulkMerge

_context.BulkMerge(rows,
    row => row.Id,
    row => new { row.Column1, row.Column2 },
    row => new { row.Column1, row.Column2, row.Column3 },
    options =>
    {
        options.BatchSize = 0;
        options.Timeout = 30;
        options.WithHoldLock = false;
        options.ReturnDbGeneratedId = true;
        options.LogTo = Console.WriteLine;
    });

BulkMatch

var contactsFromDb = _context.BulkMatch(matchedContacts,
    x => new { x.CustomerId, x.CountryIsoCode },
    options =>
    {
        options.BatchSize = 0;
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

TempTable

var customerTableName = _context.CreateTempTable(customers,
    x => new
    {
        x.IdNumber,
        x.FirstName,
        x.LastName,
        x.CurrentCountryIsoCode
    },
    options =>
    {
        options.BatchSize = 0;
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

DirectInsert

_context.DirectInsert(row,
    row => new { row.Column1, row.Column2, row.Column3 },
    options =>
    {
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

DirectUpdate

_context.DirectUpdate(row,
    row => new { row.Column3, row.Column2 },
    options =>
    {
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

DirectDelete

_context.DirectDelete(row,
    options =>
    {
        options.Timeout = 30;
        options.LogTo = Console.WriteLine;
    });

Returned Result

BulkUpdate

var updateResult = dbct.BulkUpdate(rows, row => new { row.Column3, row.Column2 });

Console.WriteLine($"Updated: {updateResult.AffectedRows} row(s)");

BulkDelete

var deleteResult = dbct.BulkDelete(rows);

Console.WriteLine($"Deleted: {deleteResult.AffectedRows} row(s)");

BulkMerge

var mergeResult = dbct.BulkMerge(rows,
    row => row.Id,
    row => new { row.Column1, row.Column2 },
    row => new { row.Column1, row.Column2, row.Column3 });

Console.WriteLine($"Updated: {mergeResult.UpdatedRows} row(s)");
Console.WriteLine($"Inserted: {mergeResult.InsertedRows} row(s)");
Console.WriteLine($"Affected: {mergeResult.AffectedRows} row(s)");

Benchmarks

BulkInsert

Single Table /src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkInsertSingleTableBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
EFCoreInsert 100 45.19 ms NA - - - 985.52 KB
BulkInsert 100 32.68 ms NA - - - 93.78 KB
EFCoreInsert 1000 145.41 ms NA 1000.0000 - - 9702.7 KB
BulkInsert 1000 44.94 ms NA - - - 573.84 KB
EFCoreInsert 10000 788.90 ms NA 14000.0000 5000.0000 - 95727.38 KB
BulkInsert 10000 126.36 ms NA - - - 5320.53 KB
EFCoreInsert 100000 7,107.29 ms NA 146000.0000 36000.0000 - 950162.56 KB
BulkInsert 100000 998.42 ms NA 7000.0000 3000.0000 1000.0000 51730.81 KB
EFCoreInsert 250000 18,542.56 ms NA 365000.0000 87000.0000 - 2352262.34 KB
BulkInsert 250000 2,576.88 ms NA 16000.0000 5000.0000 1000.0000 125832.63 KB
EFCoreInsert 500000 34,957.34 ms NA 730000.0000 170000.0000 - 4711772.88 KB
BulkInsert 500000 5,553.61 ms NA 30000.0000 9000.0000 1000.0000 252707.77 KB

Multiple Tables (1x parent rows + 5x child rows) /src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkInsertMultipleTablesBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
EFCoreInsert 100 226.22 ms NA 1000.0000 - - 7438.51 KB
BulkInsert 100 48.38 ms NA - - - 444.18 KB
EFCoreInsert 1000 566.95 ms NA 11000.0000 4000.0000 - 73518.48 KB
BulkInsert 1000 125.77 ms NA - - - 3460.21 KB
EFCoreInsert 10000 6,268.42 ms NA 114000.0000 30000.0000 - 731076.92 KB
BulkInsert 10000 1,066.74 ms NA 5000.0000 2000.0000 1000.0000 33324.16 KB
EFCoreInsert 100000 59,389.89 ms NA 1138000.0000 264000.0000 - 7282561.93 KB
BulkInsert 100000 9,504.12 ms NA 39000.0000 13000.0000 1000.0000 327100.08 KB

BulkUpdate

/src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkUpdateBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
EFCoreUpdate 100 61.65 ms NA - - 853.66 KB
BulkUpdate 100 27.33 ms NA - - 63.55 KB
EFCoreUpdate 1000 143.39 ms NA 1000.0000 - 8398.1 KB
BulkUpdate 1000 43.95 ms NA - - 379.25 KB
EFCoreUpdate 10000 685.97 ms NA 12000.0000 3000.0000 82396.19 KB
BulkUpdate 10000 182.54 ms NA - - 3499.74 KB
EFCoreUpdate 100000 8,495.18 ms NA 120000.0000 28000.0000 810248.07 KB
BulkUpdate 100000 2,091.42 ms NA 5000.0000 1000.0000 33819.46 KB
EFCoreUpdate 250000 17,859.49 ms NA 300000.0000 69000.0000 2005895.77 KB
BulkUpdate 250000 4,290.07 ms NA 13000.0000 7000.0000 84352 KB
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
BulkUpdate 500000 10.19 s NA 27000.0000 16000.0000 164.63 MB
BulkUpdate 1000000 17.03 s NA 54000.0000 37000.0000 329.12 MB

BulkDelete

/src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkDeleteBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
EFCoreDelete 100 73.25 ms NA - - 681.09 KB
BulkDelete 100 29.42 ms NA - - 43.45 KB
EFCoreDelete 1000 176.83 ms NA 1000.0000 1000.0000 6745 KB
BulkDelete 1000 27.19 ms NA - - 236.86 KB
EFCoreDelete 10000 1,489.03 ms NA 10000.0000 2000.0000 66031.55 KB
BulkDelete 10000 431.74 ms NA - - 2150.99 KB
EFCoreDelete 20000 6,084.87 ms NA 20000.0000 7000.0000 132403.3 KB
BulkDelete 20000 276.52 ms NA - - 4276.01 KB
EFCoreDelete 50000 39,933.60 ms NA 49000.0000 14000.0000 326164.25 KB
BulkDelete 50000 1,477.09 ms NA 1000.0000 - 10594.63 KB
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
BulkDelete 100000 937.7 ms NA 3000.0000 1000.0000 20.67 MB
BulkDelete 250000 2,619.7 ms NA 7000.0000 3000.0000 51.7 MB
BulkDelete 500000 4,897.7 ms NA 13000.0000 6000.0000 103.22 MB
BulkDelete 1000000 9,466.0 ms NA 26000.0000 12000.0000 206.28 MB

BulkMerge

/src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkMergeBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
EFCoreUpsert 100 82.11 ms NA - - - 1840.23 KB
BulkMerge 100 34.27 ms NA - - - 162.96 KB
EFCoreUpsert 1000 266.86 ms NA 2000.0000 1000.0000 - 17984.91 KB
BulkMerge 1000 79.45 ms NA - - - 1213.33 KB
EFCoreUpsert 10000 1,451.20 ms NA 26000.0000 8000.0000 - 178385.15 KB
BulkMerge 10000 677.47 ms NA 1000.0000 - - 11679.42 KB
EFCoreUpsert 100000 13,902.06 ms NA 266000.0000 63000.0000 - 1762696.52 KB
BulkMerge 100000 3,415.31 ms NA 16000.0000 6000.0000 1000.0000 115233.2 KB
EFCoreUpsert 250000 36,167.51 ms NA 665000.0000 152000.0000 - 4362872.57 KB
BulkMerge 250000 7,681.71 ms NA 37000.0000 11000.0000 1000.0000 284187.09 KB

/src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkMergeReturnDbGeneratedIdBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
ReturnDbGeneratedId 100 38.45 ms NA - - - 151.09 KB
NotReturnDbGeneratedId 100 37.75 ms NA - - - 116.8 KB
ReturnDbGeneratedId 1000 67.42 ms NA - - - 1099.48 KB
NotReturnDbGeneratedId 1000 60.02 ms NA - - - 769.23 KB
ReturnDbGeneratedId 10000 783.73 ms NA 1000.0000 - - 10543.62 KB
NotReturnDbGeneratedId 10000 501.07 ms NA 1000.0000 - - 7348.79 KB
ReturnDbGeneratedId 100000 3,187.89 ms NA 14000.0000 5000.0000 1000.0000 103878.09 KB
NotReturnDbGeneratedId 100000 2,741.31 ms NA 11000.0000 5000.0000 1000.0000 72936.01 KB
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
ReturnDbGeneratedId 250000 7.799 s NA 32000.0000 8000.0000 - 249.8 MB
NotReturnDbGeneratedId 250000 6.619 s NA 24000.0000 7000.0000 - 177.7 MB
ReturnDbGeneratedId 500000 15.051 s NA 66000.0000 19000.0000 1000.0000 500.64 MB
NotReturnDbGeneratedId 500000 14.328 s NA 47000.0000 14000.0000 - 355.19 MB
ReturnDbGeneratedId 1000000 32.449 s NA 129000.0000 34000.0000 - 1003.67 MB
NotReturnDbGeneratedId 1000000 28.253 s NA 95000.0000 28000.0000 - 710.22 MB

BulkMatch

Single Column /src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkMatchSingleColumnBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
EFCoreSelect 100 97.373 ms NA - - - 1008.33 KB
EFCoreBatchSelect 100 7.166 ms NA - - - 94.77 KB
BulkMatch 100 8.570 ms NA - - - 106.63 KB
EFCoreSelect 1000 720.250 ms NA 1000.0000 - - 9761.42 KB
EFCoreBatchSelect 1000 6.375 ms NA - - - 908.18 KB
BulkMatch 1000 15.445 ms NA - - - 820.36 KB
EFCoreSelect 10000 8,075.686 ms NA 15000.0000 1000.0000 - 97115.62 KB
EFCoreBatchSelect 10000 66.438 ms NA 1000.0000 - - 9092.91 KB
BulkMatch 10000 69.430 ms NA 1000.0000 - - 8177.76 KB
EFCoreSelect 100000 81,088.718 ms NA 159000.0000 31000.0000 1000.0000 972204.7 KB
EFCoreBatchSelect 100000 920.412 ms NA 11000.0000 4000.0000 1000.0000 91808.56 KB
BulkMatch 100000 742.030 ms NA 13000.0000 6000.0000 1000.0000 82419.43 KB
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
EFCoreBatchSelect 250000 2.101 s NA 26000.0000 11000.0000 1000.0000 224.05 MB
BulkMatch 250000 2.067 s NA 32000.0000 12000.0000 1000.0000 201.64 MB
EFCoreBatchSelect 500000 4.239 s NA 53000.0000 20000.0000 2000.0000 448.85 MB
BulkMatch 500000 4.507 s NA 62000.0000 24000.0000 1000.0000 404.03 MB
EFCoreBatchSelect 1000000 8.523 s NA 103000.0000 38000.0000 1000.0000 898.44 MB
BulkMatch 1000000 11.585 s NA 123000.0000 46000.0000 1000.0000 808.82 MB

Multiple Columns /src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/BulkMatchMultipleColumnsBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
EFCoreSelect 100 130.11 ms NA - - 1256.8 KB
BulkMatch 100 15.46 ms NA - - 173.56 KB
EFCoreSelect 1000 997.87 ms NA 2000.0000 - 12373.85 KB
BulkMatch 1000 43.35 ms NA - - 1358.77 KB
EFCoreSelect 10000 9,769.96 ms NA 20000.0000 4000.0000 123595.97 KB
BulkMatch 10000 238.80 ms NA 2000.0000 1000.0000 13768.49 KB
EFCoreSelect 100000 89,204.16 ms NA 201000.0000 51000.0000 1237424.23 KB
BulkMatch 100000 2,612.00 ms NA 21000.0000 8000.0000 138686.52 KB
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Allocated
BulkMatch 250000 6.709 s NA 53000.0000 19000.0000 340.68 MB
BulkMatch 500000 12.939 s NA 107000.0000 36000.0000 683.46 MB
BulkMatch 1000000 25.418 s NA 214000.0000 74000.0000 1369.34 MB

TempTable

/src/EntityFrameworkCore.SqlServer.SimpleBulks.Benchmarks/TempTableBenchmarks.cs

BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.5011)
11th Gen Intel Core i7-1165G7 2.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=8.0.400
  [Host]     : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
  Job-LGAVYD : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2

InvocationCount=1  IterationCount=1  UnrollFactor=1  
WarmupCount=0  
Method RowsCount Mean Error Gen0 Gen1 Gen2 Allocated
CreateTempTable 100 7.639 ms NA - - - 68.03 KB
CreateTempTable 1000 14.077 ms NA - - - 373.76 KB
CreateTempTable 10000 89.789 ms NA - - - 3455.46 KB
CreateTempTable 100000 574.937 ms NA 4000.0000 1000.0000 - 34081.95 KB
CreateTempTable 250000 1,403.071 ms NA 12000.0000 5000.0000 1000.0000 85229.91 KB
CreateTempTable 500000 2,838.562 ms NA 22000.0000 8000.0000 1000.0000 170241.85 KB
CreateTempTable 1000000 6,198.206 ms NA 43000.0000 14000.0000 1000.0000 340282.7 KB

License

EntityFrameworkCore.SqlServer.SimpleBulks is licensed under the MIT license.