Linq Query Optimization joining of tables - asp.net-mvc

So I have a linq query, where s1.code comes from an object before this linq query.
var q1 = from cf in db.Control_Franchises
join t1 in db.Territories
on SqlFunctions.StringConvert((double)cf.FranchiseID).Trim()
equals t1.FranchiseID.Trim()
join cu in db.Control_Users on t1.FK_CompanyID equals cu.PrimaryCompanyID
join u in db.Users on cu.UserID.ToLower() equals u.Username.ToLower()
where cf.Status == "ACTIVE"
&& cf.FranchiseID > 1000
&& cu.UserType == "Franchisee"
&& cu.Status == "ACTIVE"
&& t1.Province == s1.Code
orderby cu.LastName ascending, cf.FranchiseID ascending
select new
{
FranchiseId = cf.FranchiseID,
Province = cf.StateCode,
DisplayName = cu.LastName + ", " + cu.FirstName,
UserId = u.PK_UserID
};
I have the same block of code but this time in my where clause, I changed the filter from using t1.Province == s1.Code to cf.StateCode == s1.Code
var q1 = from cf in db.Control_Franchises
join t1 in db.Territories
on SqlFunctions.StringConvert((double)cf.FranchiseID).Trim()
equals t1.FranchiseID.Trim()
join cu in db.Control_Users on t1.FK_CompanyID equals cu.PrimaryCompanyID
join u in db.Users on cu.UserID.ToLower() equals u.Username.ToLower()
where cf.Status == "ACTIVE"
&& cf.FranchiseID > 1000
&& cu.UserType == "Franchisee"
&& cu.Status == "ACTIVE"
&& cf.StateCode == s1.Code // DIFFERENT FROM ABOVE
orderby cu.LastName ascending, cf.FranchiseID ascending
select new
{
FranchiseId = cf.FranchiseID,
Province = cf.StateCode,
DisplayName = cu.LastName + ", " + cu.FirstName,
UserId = u.PK_UserID
};
Now the first query runs 10 times as fast as the second one.
How I am measuring the speed though, is the load time of my Edit Page, which in turn is loading a mvc tree view of the nodes. This query as well portions of a different query.
Now I'm trying to understand why my first query loads much faster and the only reasoning I can think of is because I am doing a condition on a table that will be joined, so rather then joining the entire "Territories" table with "Control_Franchises" I am only joining a portion of the "Territories" table.
Any thoughts?

Most likely the two different columns t1.Province and cf.StateCode are indexed differently in underlying data source (or one isn't at all)

Related

Improve EF Linq query performance

I have this problem where I need to perform a Linq query on a big table (1m records) joining other smaller tables. Running the query is taking too long and sometimes ending in a Execution Timeout Expired. I am not sure how to improve the query to cut execution time.
var result = from p in db.population
join e in db.engineers on p.id equals e.personId into ps
from e in ps.DefaultIfEmpty()
where (e == null || e.activity == "student")
select p.name;
var final result = result.Take(100).ToList();
Basically I want to get the first 100 persons from db.population who are not an engineer, engineer-students are excluded.
I am not sure if the query can be written in a better way to improve performance ?
Try This
Do it Before join
var result = from p in db.population
join e in db.engineers.WHERE( c=> c.activity == "student")
on p.id equals e.personId into ps
from e in ps.DefaultIfEmpty()
where (e == null)
select p.name;
var final result = result.Take(100).ToList();
or
join e in db.engineers.WHERE( c=> c.activity == "student").Take(100)

Linq left outer join not working using DefaultIfEmpty

Using the technique found on the MSDN article "How to: Perform Left Outer Joins (C# Programming Guide)", I attempted to create a left outer join in my Linq code. The article mentions using the DefaultIfEmpty method in order to create a left outer join from a group join. Basically, it instructs the program to include the results of the left (first) collection even if there are no results in the right collection.
The way this program executes, however, it does so as if the outer join has not been specified.
In our database, AgentProductTraining is a collection of courses our agents have taken. Normally you cannot enter a Course onto it's appropriate table without entering a corresponding value into the CourseMaterials table. However, occasionally this may happen, so we want to make sure we return results even when a Course is listed in AgentProductTraining without any corresponding information in CourseMaterials.
var training = from a in db.AgentProductTraining
join m in db.CourseMaterials on a.CourseCode equals m.CourseCode into apm
where
a.SymNumber == id
from m in apm.DefaultIfEmpty()
where m.EffectiveDate <= a.DateTaken
&& ((m.TerminationDate > a.DateTaken) | (m.TerminationDate == null))
select new
{
a.AgentProdTrainId,
a.CourseCode,
a.Course.CourseDescription,
a.Course.Partner,
a.DateTaken,
a.DateExpired,
a.LastChangeOperator,
a.LastChangeDate,
a.ProductCode,
a.Product.ProductDescription,
m.MaterialId,
m.Description,
a.Method
};
The MSDN example uses a new variable subpet:
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
So you must use your own "subpet", I rewrote your code using the submat variable:
var training = from a in db.AgentProductTraining
join m in db.CourseMaterials on a.CourseCode equals m.CourseCode into apm
where
a.SymNumber == id
from submat in apm.DefaultIfEmpty()
where
(submat.EffectiveDate <= a.DateTaken || submat.EffectiveDate == null) &&
(submat.TerminationDate > a.DateTaken || submat.TerminationDate == null)
select new
{
a.AgentProdTrainId,
a.CourseCode,
a.Course.CourseDescription,
a.Course.Partner,
a.DateTaken,
a.DateExpired,
a.LastChangeOperator,
a.LastChangeDate,
a.ProductCode,
a.Product.ProductDescription,
MaterialId = (submat==null?-1:submat.MaterialId),
Description = (submat==null?String.Empty:submat.Description),
a.Method
};

Mvc Telerik grid With large database

I am using telerik mvc grid in my mvc project , my table have around 1 Million records. My grid taking too much time to load.
This is my Query
//
var bib = (from a in db.Bibs
join inf in db.InfoTypes
on a.InfoTypeId equals inf.Id
where a.Status == "A"
select new BibViewModel
{
Id = a.Id,
Type = inf.Type,
InfoType = inf.Description,
Title = (from asd in db.BibContents where asd.BibId == a.Id && asd.TagNo == "245" && asd.Sfld == "a" select asd.Value).FirstOrDefault(),
Author = (from asd in db.BibContents where asd.BibId == a.Id && asd.TagNo == "100" && asd.Sfld == "a" select asd.Value).FirstOrDefault(),
CatalogueDate = a.CatalogDate,
Contents = "",
CreatedOn = a.CreatedOn,
ItemRelation = db.Items.Any(item => item.BibId == a.Id),
IssueRelation = db.Issues.Any(item => item.BibId == a.Id),
});
return View(new GridModel(bib.OrderByDescending(x => x.CreatedOn).Tolist()));
ToList() actually invokes the query, so if calling ToList() is taking too long, that means the issue is with the query.
In LINQ, you can use paging like in the following post; the idea is to use Skip and Take to skip X records, and only take Y records, as in:
var results = (from .. select ..).Skip(X).Take(Y)
With 1M records, I would highly suggest replacing it with a stored procedure, which will be much, much faster for what you are trying to do. Consider a custom pagination approach, which works very well for me with large result sets:
http://www.neiland.net/blog/article/dynamic-paging-in-sql-server-stored-procedures/
http://www.beansoftware.com/ASP.NET-Tutorials/Paging-Stored-Procedures.aspx
http://www.sqlpointers.com/2009/10/custom-sorting-and-paging-in-sql-server.html
T-SQL stored procedure with sorting and paging enabled not working properly
If you can't use stored procedures, reading this will help understand what needs to be accomplished with pagination. With LINQ, you'll want to examine the SQL being generated to see where you also can fine-tune the query, either using SQL profiler, or LINQPad.

Need help to build an EF query with LEFT JOIN

I can't find the correct way to build an EF (4.1) query that will return the same result as this SQL containing a LEFT JOIN:
SELECT
s.id_service,
s.description,
x.id_service as isDisponible
FROM
role.service_disponible s
LEFT JOIN
role.service_disponible_x_ue x
ON s.id_service = x.id_service AND x.id_ue = 1 and flg_actif = '1'
In fact I'm just trying to obtain the complete list of services disponible (ServiceDisponible) adding a field that tell me if service is disponible for a specific entity (filtered with the id_ue) which information come from a many to many related table (ServiceDisponibleXUe).
My model is:
Ideally, I would like this query to return this viewModel object what is basically my serviceDisponible domain with one more field indicating the disponibility of the service.
public ServiceDisponibleViewModel(ServiceDisponible ServiceDisponible, bool isDisponible)
{
this.serviceDisponible = serviceDisponible;
this.isDisponible = isDisponible;
}
What I have so far is this query but the syntax is invalid:
services = context.ServiceDisponible
.Select(a => new ServiceDisponibleViewModel
{
c => new ServiceDisponible
{
id_service = a.id_service,
description = a.description
},
isDisponible = a.ServiceDisponibleXUe
.Any(b => b.flg_actif && b.id_ue == idUe)
}).ToList();
Try this:
ServiceDisponibleViewModel services =
from sd in context.ServiceDisponible
from sdx in context.ServiceDisponibleXUe
.Where(x => x.id_ue == 1 && flg_actif == '1' && x.id_service == sd.id_service)
.DefaultIfEmpty()
select new ServiceDisponibleViewModel(
new ServiceDisponible
{
id_service = sd.id_service,
description = sd.description
},
sdx.id_service
);
Having SQL as example often makes one jump to a join in linq. But using navigation properties produces much more succinct syntax:
from sd in context.ServiceDisponible
from sdx in sd.ServiceDisponibleXUes.Where(x => x.id_ue == 1
&& x.flg_actif == "1")
.DefaultIfEmpty()
select new
{ sd.id_service,
sd.description,
isDisponible = sdx.id_service
};
(I couldn't help using the plural form of ServiceDisponibleXUe which imo is more clear).

Not getting data of Include object -- Entity Framework

I am getting the problem with "Include" in Entity Framework. Lets assume that I have two tables with foreign key relation.
var result = (from u in entity.Table1.Include("Table2")
join o in entity.Table2 on u.Column1 equals o.Column1
where u.Column2 == “abc” && u.Column3 == ‘xyz’
&& o.Column5 == organizationCode
select u).FirstOrDefault();
With the above query its not returning the Table2 object data in the result even though I have proper data in the database.
The issue i have found with above query is, if query is having "Include" as well as "Join", EF not considering "Include" tables. This is my assumption.
After spending some time I got the data by writing a dummy query below that. Please see the both queries below.
var result = (from u in entity.Table1.Include("Table2")
join o in entity.Table2 on u.Column1 equals o.Column1
where u.Column2 == “abc” && u.Column3 == ‘xyz’
&& o.Column5 == organizationCode
select u).FirstOrDefault();
var resultOrg = (from o in entity. Table2
where o.Column5 == organizationCode
select o).FirstOrDefault();
After executing both queries I am getting the Include (Table2) data in the result variable. In this case unnecessarily I am executing one query which I want to avoid.
Please suggest me where we are doing wrong.
You cannot use Include if you are using join. There is now way around that. Moreover what you are trying to do is filtering include which is also not possible.
You can do this:
var result = (from u in entity.Table1.Include("Table2")
where u.Column2 == “abc” && u.Column3 == ‘xyz’ &&
u.Table2.Any(o => o.Column5 == organizationCode)
select u).FirstOrDefault();
But it will include all Table2 entities to filtered Table1 entities. You cannot restrict included values to only those having some organization code.
To filter navigation properties you must use projection:
var result = (from u in entity.Table1
where u.Column2 == “abc” && u.Column3 == ‘xyz’ &&
u.Table2.Any(o => o.Column5 == organizationCode)
select new
{
Table1 = u
Table2 = u.Table2.Where(o => o.Column5 == organizationCode)
}).FirstOrDefault();
You must project either to anonymous type or custom type.
The reason why your second query works is automatic wiring of relations for tracked properties and it is another way how to filter relations but in such case this is enough:
var result = (from u in entity.Table1
where u.Column2 == “abc” && u.Column3 == ‘xyz’ &&
u.Table2.Any(o => o.Column5 == organizationCode)
select u).FirstOrDefault();
var resultOrg = (from o in entity. Table2
where o.Column5 == organizationCode
select o).FirstOrDefault();

Resources