question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Inefficient SQL generated for Bulk Update from in-memory collection

See original GitHub issue

Hi,

I am attempting to design a generic ‘bulk update’ method which uses a temp table to store the externally updated rows and joins the temp table with the actual table to do the update operation efficiently:

public void UpdateRange<T>(IEnumerable<T> source) where T : class, IEntity
{
    using var connection = _context.CreateLinqToDbConnection();

    connection.BeginTransaction();

    using var tempTable = connection.CreateTempTable(source, tableName: $"{typeof(T).Name}UpdateTemp");

    var entityTable = connection.GetTable<T>();

    var updates = from e in entityTable
        join te in tempTable on e.Id equals te.Id into gj
        from te in gj
        select te;

    updates.Update(entityTable, e => e);

    connection.CommitTransaction();
}

I use this strategy as opposed to a MERGE statement to support RDBMS that don’t support MERGE.

When working with the following test model and interfaces:

public interface IEntity
{
    object Id { get; set; }
}

public interface IEntity<T> : IEntity
{
    new T Id { get; set; }
}

public abstract class Entity<T> : IEntity<T>
{
    public T Id { get; set; }

    object IEntity.Id
    {
        get => Id;
        set => Id = value != null ? (T) value : default;
    }
}

public class Person : Entity<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The following SQL is generated:

UPDATE
	[People]
SET
	[Id] = (
		SELECT
			[gj].[Id]
		FROM
			[People] [e]
				INNER JOIN [PersonUpdateTemp] [gj] ON [e].[Id] = [gj].[Id]
		WHERE
			[People].[Id] = [e].[Id]
	),
	[LastName] = (
		SELECT
			[gj_1].[LastName]
		FROM
			[People] [e_1]
				INNER JOIN [PersonUpdateTemp] [gj_1] ON [e_1].[Id] = [gj_1].[Id]
		WHERE
			[People].[Id] = [e_1].[Id]
	),
	[FirstName] = (
		SELECT
			[gj_2].[FirstName]
		FROM
			[People] [e_2]
				INNER JOIN [PersonUpdateTemp] [gj_2] ON [e_2].[Id] = [gj_2].[Id]
		WHERE
			[People].[Id] = [e_2].[Id]
	)
WHERE
	EXISTS(
		SELECT
			*
		FROM
			[People] [e_3]
				INNER JOIN [PersonUpdateTemp] [gj_3] ON [e_3].[Id] = [gj_3].[Id]
		WHERE
			[People].[Id] = [e_3].[Id]
	)

I was hoping to have a single join and update statement updating each column from the join result. How would I accomplish this?

I have a repo that contains a test that produces the above SQL here (see the Linq2DbUpdateTests class). I retrieved the SQL by setting a breakpoint in the TestService class on the last line of the method connection.CommitTransaction(); and inspecting the Command property’s SQLText property.

Environment details

linq2db version: 3.2.3 Database Server: Sqlite Database Provider: EF Core (via Linq2db.EntityFrameworkCore Operating system: Windows 10 .NET Framework: .NET Core

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
sdanylivcommented, Feb 18, 2021

I have written this UPDATE for SQLite approx 4 years ago. So it’s time to review this part.

0reactions
MaceWinducommented, Mar 30, 2022

Actually, we will try to fix it for next release too

Read more comments on GitHub >

github_iconTop Results From Across the Web

Efficient bulk SQL database table update based on the ...
I have over 1 million rows that I check for changes and then update. I completed my program that goes over each record...
Read more >
Slow update on large table with subquery
Full script to generate a fake data set and try out the new approach ... substrings is independent for each batch and easily...
Read more >
Troubleshoot slow SQL Server performance caused by I/O ...
Provides a methodology to isolate and troubleshoot SQL performance problems caused by slow disk I/O.
Read more >
How to Update millions or records in a table - Ask TOM
If you have a large bulk update that is done once and hits most of the of rows -- you may be best...
Read more >
SQL Server performance counters (Batch Requests/sec or ...
SQL batches ensures creation of a single query execution plan; Variables created within a batch cannot be used outside of the batch; Multiple ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found