Tuesday, September 3, 2019

c# - IEnumerable extension methods called on IQueryable causing performance issues

Whenever I call an extension method that accepts an IEnumerable on an IQueryable, the remainder of the process where that list/entity is being used in is incredibly slow.



POR QUEEEEE?!



The problem doesn't seem to be related to the actual structure of the code, as it's otherwise optimal, and when I spin up a new database for unit testing it, the problem doesn't seem to appear.



This is the extension method:



        public static Bill FirstById(this IEnumerable query, int billId)

{
return query.FirstOrDefault(r => r.Id == billId);
}


This is how it's being used:



        public Bill GetDeposit(int depositId)
{
var deposit = _depositRepository

.AndSalesOrder()
.AndSalesOrderCustomerContact()
.AndDepositApplications()
.FirstById(depositId);

return deposit;
}


And this is how the actual entity is being used:




        public bool ConvertDeposit(List conversions)
{
if (conversions.Any())
{
var depositId = conversions.Select(c => c.DepositId)
.Distinct()
.Single();

var billPaymentIds = conversions.Select(c => c.BillPaymentId);


var deposit = _dataProvider.GetDeposit(depositId);

var billPayments = _dataProvider.GetBillPayments(billPaymentIds);

var totalConversionAmount = conversions.Sum(c => c.Amount);

var unappliedDepositAmount = (deposit.BillStatusId == BillStatus.Credited ? 0 : deposit.TotalSell - deposit.Balance) - deposit.DepositApplications.Select(a => a.Amount).DefaultIfEmpty(0).Sum();

if (unappliedDepositAmount != totalConversionAmount)

{
throw new Exception("The provided conversion amount would not fully convert the Deposit.");
}

_unitOfWork.TryTransactionAndCommit(() =>
{

foreach (var conversion in conversions)
{
var billPayment = billPayments.FirstByBillPaymentId(conversion.BillPaymentId);



this.CreateBillPaymentBill(deposit, conversion);

this.CreateMoneyOnAccountTransaction(deposit, conversion);

this.UpdateBillPayment(conversion, billPayment);
}

this.UpdateNetProceeds(billPayments);


this.ApplyCreditCardFees(billPaymentIds);

var customerCredit = this.CreateCustomerCredit(deposit, totalConversionAmount);

this.CreateCustomerCreditBill(deposit, customerCredit);

this.UpdateDeposit(deposit, totalConversionAmount);
});
}

else
{
throw new Exception("The provided set of bill payments was empty.");
}

return true;
}


We're seeing that each method, which has been tested rigorously, is producing the following diagnostic results:




PV2ANZAC                
GetDeposit: 33434ms
GetBillPayments: 54ms
CreateBillPaymentBill1: 17775ms
CreateMoneyOnAccountTransaction1: 10774ms
UpdateBillPayment1: 10810ms
UpdateNetProceeds: 18130ms
ApplyCreditCardFees: 17206ms
Insert CustomerCredit: 10795ms

CustomerCredit SaveChanges: 16276ms
CreateCustomerCredit: 27075ms
CreateCustomerCreditBill: 10688ms


And we are definitely expecting everything to be at least an order of magnitude less than what it is.

No comments:

Post a Comment

hard drive - Leaving bad sectors in unformatted partition?

Laptop was acting really weird, and copy and seek times were really slow, so I decided to scan the hard drive surface. I have a couple hundr...