Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UpdateAll deadlocks #24

Open
Kraviecc opened this issue Dec 12, 2019 · 7 comments
Open

UpdateAll deadlocks #24

Kraviecc opened this issue Dec 12, 2019 · 7 comments

Comments

@Kraviecc
Copy link

Hi,

sometimes there is a problem when using UpdateAll method by multiple separate applications/threads (updating different records). Due to the fact that standard behavior is updating rows using PAGELOCK, deadlocks may occur.

Maybe it's worth to add an additional option to specify lock type for the query (ROWLOCK/TABLOCK/PAGLOCK)?

@RudeySH
Copy link
Owner

RudeySH commented Dec 12, 2019

Under the hood, UpdateAll uses SqlBulkCopy which uses row locks by default. At least, that's what the documentation says. Perhaps SQL Server is escalating the row locks to page locks in your database?

My fork of EFUtilities allows you to specify SqlBulkCopyOptions. There's an option to use table locks instead of row locks. See https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopyoptions

Does that help resolving your deadlocks?

@Kraviecc
Copy link
Author

If I understand correctly how it works, it uses SqlBulkCopy only to create temp table.

The problem is when UPDATE statement is executed (I mean this line: https://github.com/RudeySH/EntityFramework.Utilities/blob/master/EntityFramework.Utilities/EntityFramework.Utilities/SqlQueryProvider.cs#L134).

When updating table we can write query which contains suggestion for the query optimizer to use different type of locks, like: UPDATE table with (ROWLOCK)...

Anyway if I'm wrong, I can use table lock but it will impact performance in my case.

@RudeySH
Copy link
Owner

RudeySH commented Dec 12, 2019

You're right, my bad. The SqlBulkCopyOptions will only be used for inserting data into the temporary table. Perhaps you can implement a IDbCommandInterceptor that rewrites the UPDATE statement before it's executed? That would give you control over what query hints (ROWLOCK/TABLOCK/PAGLOCK) will be used.

You can read more about interception here:

Although, I am not 100% certain that EF will be able to intercept the commands sent by EFUtilities.

@Kraviecc
Copy link
Author

Thanks for the suggestion. I'll try to implement interceptor and will share my thoughts afterwards.

@RudeySH
Copy link
Owner

RudeySH commented Apr 10, 2020

Did you have any luck implementing an interceptor?

@Kraviecc
Copy link
Author

I tried it last week but without a success. These operations don't go through "normal" EF's flow so they cannot be intercepted.

@RudeySH
Copy link
Owner

RudeySH commented Jun 22, 2024

Support for table hints will be added in v2. I have just published 2.0.0-alpha.1 on NuGet.

This is all subject to change, but right now it works like this:

var options = SqlUpdateAllOptions
{
    TableHints = new[] { "ROWLOCK" },
};

EFBatchOperation
    .For(db, db.Comments)
    .UpdateAll(comments, x => x.ColumnsToUpdate(c => c.Reads), options);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants