I have a table as shown below. It has accounts of type Fixed and Savings. I need to update the status of all accounts of user 1. There are 10000 accounts for this user. Essentially the logic would be as shown in the following SQL Stored Procedure Script. The script takes only less than 1 second to execute (83 milli seconds).
But when I converted it to a ORM using LINQ to SQL it takes more than 3 minutes (204814 milli seconds). It is at least 240,000% slower.
Is there a pattern in LINQ to SQL (or other ORM) that will help to overcome this performance hit?
What can force it to do a update in one go to database?
Note: I am aware of calling stored procedures from LINQ. I don’t see that as ORM and not an option for me.

Manual Stored Procedure Script
DECLARE @UserID INT
DECLARE @StatusForFixed VARCHAR(50)
DECLARE @StatusForSavings VARCHAR(50)
SET @UserID = 1
SET @StatusForFixed = 'FrozenFA11'
SET @StatusForSavings = 'FrozenSB22'
UPDATE BankAccount
SET Status =
CASE
WHEN BankAccount.AccountType='Fixed' THEN @StatusForFixed
WHEN BankAccount.AccountType='Savings' THEN @StatusForSavings
END
WHERE AccountOwnerID=@UserID
LINQ Generated Code Sample
Note: This type of statements happen 10000 times
UPDATE [dbo].[BankAccount]
SET [Status] = @p3
WHERE [BankAccountID] = @p0
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [3585]
-- @p3: Input NChar (Size = 10; Prec = 0; Scale = 0) [FrozenSB]
CODE after applying ORM
public class BankAccountAppService
{
public RepositoryLayer.ILijosBankRepository AccountRepository { get; set; }
public void FreezeAllAccountsForUser(int userId)
{
IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
foreach (DBML_Project.BankAccount acc in accounts)
{
acc.Freeze();
}
AccountRepository.UpdateAccount();
}
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
public System.Data.Linq.DataContext Context
{
get;
set;
}
public List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID)
{
IQueryable<DBML_Project.BankAccount> queryResultEntities = Context.GetTable<DBML_Project.BankAccount>().Where(p => p.AccountOwnerID == userID);
return queryResultEntities.ToList();
}
public List<T> GetAllAccountsofType<T>() where T : DBML_Project.BankAccount
{
var query = from p in Context.GetTable<DBML_Project.BankAccount>().OfType<T>()
select p;
List<T> typeList = query.ToList();
return typeList;
}
public virtual void UpdateAccount()
{
Context.SubmitChanges();
}
}
namespace DBML_Project
{
public partial class BankAccount
{
//Define the domain behaviors
public virtual void Freeze()
{
//Do nothing
}
}
public class FixedBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenFA";
}
}
public class SavingsBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenSB";
}
}
}
REFERENCE
You are comparing two wildly different scenarios:
1: running a script locally on the SQL server, a single set-based
UPDATE2: fetching 10,000 records over the network, updating each, submitting each individually
You can improve 2 a bit by deferring the
SubmitChanges()into one single batch of 10,000 rather than 10,000 batches of 1 (just: don’t callSubmitChanges()until the end), but that still involves sending the details of 10,000 records in two directions, plus all the overheads (for example,SubmitChanges()might still choose to do that via 10,000 individual calls).Basically, object-based tools are not intended for bulk updates against records. If the SP works, use the SP. Maybe call the SP via a data-context, just for convenience of it adding the method/parameters/etc.