Linq2SQL: optimize a query?

Is there any way to optimize the following query:

The goal is to try to find customers of type 4, which also exists as type2 based on their VAT and email. A customer may have one or more customers.

(I have all the relevant indexes, I promise)

from e in Clients.Where(h => h.ClientTypeId==4) join u in ClientUsers on e.Id equals u.ClientId where e.DeleteFlag.Equals("n") && ( (!(e.VAT == null || e.VAT.Equals("")) && Clients.Any(f => f.ClientTypeId == 2 && f.VAT.Equals(e.VAT))) || (!(e.Email == null || e.Email.Equals("")) && ( Clients.Any(f => f.ClientTypeId == 2 && f.Email.ToLower().Equals(e.Email.ToLower())) || (from f in ClientUsers join q in Clients on f.ClientId equals q.Id where f.Email.Equals(e.Email.ToLower()) && q.ClientTypeId == 2 select f.Id).Any() ) ) || (!(u.Email == null || u.Email.Equals("")) && ( Clients.Any(f => f.ClientTypeId == 2 && f.Email.ToLower().Equals(u.Email.ToLower())) || (from f in ClientUsers join q in Clients on f.ClientId equals q.Id where f.Email.Equals(u.Email.ToLower()) && q.ClientTypeId == 2 select f.Id).Any() ) ) ) select e 

Results in:

 -- Region Parameters DECLARE @p0 VarChar(1) SET @p0 = 'n' DECLARE @p1 NVarChar(1) SET @p1 = '' DECLARE @p2 Int SET @p2 = 2 DECLARE @p3 NVarChar(1) SET @p3 = '' DECLARE @p4 Int SET @p4 = 2 DECLARE @p5 Int SET @p5 = 2 DECLARE @p6 NVarChar(1) SET @p6 = '' DECLARE @p7 Int SET @p7 = 2 DECLARE @p8 Int SET @p8 = 2 DECLARE @p9 Int SET @p9 = 4 -- EndRegion SELECT [t0].[Id], [t0].[AccountId], [t0].[CompanyName], [t0].[Address], [t0].[Address2], [t0].[PostCode], [t0].[PostArea], [t0].[ContactPerson], [t0].[Phone], [t0].[Email], [t0].[VAT], [t0].[Webpage], [t0].[Description], [t0].[Active], [t0].[PreRegcode], [t0].[PreRegcheck], [t0].[AccountCreated], [t0].[UpdateTimeStamp], [t0].[DeleteFlag], [t0].[ClientTypeId], [t0].[CampaignCodeId], [t0].[PayexId], [t0].[ApiKey], [t0].[InvoiceName], [t0].[Source], [t0].[ProspectStatusId], [t0].[ProspectLastCommentId], [t0].[ProspectCallbackDate] FROM [Clients] AS [t0] INNER JOIN [ClientUsers] AS [t1] ON ([t0].[Id]) = [t1].[ClientId] WHERE ([t0].[DeleteFlag] = @p0) AND (((NOT (([t0].[VAT] IS NULL) OR ([t0].[VAT] = @p1))) AND (EXISTS( SELECT NULL AS [EMPTY] FROM [Clients] AS [t2] WHERE ([t2].[ClientTypeId] = @p2) AND ([t2].[VAT] = [t0].[VAT]) ))) OR ((NOT (([t0].[Email] IS NULL) OR ([t0].[Email] = @p3))) AND ((EXISTS( SELECT NULL AS [EMPTY] FROM [Clients] AS [t3] WHERE ([t3].[ClientTypeId] = @p4) AND (LOWER([t3].[Email]) = LOWER([t0].[Email])) )) OR (EXISTS( SELECT NULL AS [EMPTY] FROM [ClientUsers] AS [t4] INNER JOIN [Clients] AS [t5] ON [t4].[ClientId] = ([t5].[Id]) WHERE ([t4].[Email] = LOWER([t0].[Email])) AND ([t5].[ClientTypeId] = @p5) )))) OR ((NOT (([t1].[Email] IS NULL) OR ([t1].[Email] = @p6))) AND ((EXISTS( SELECT NULL AS [EMPTY] FROM [Clients] AS [t6] WHERE ([t6].[ClientTypeId] = @p7) AND (LOWER([t6].[Email]) = LOWER([t1].[Email])) )) OR (EXISTS( SELECT NULL AS [EMPTY] FROM [ClientUsers] AS [t7] INNER JOIN [Clients] AS [t8] ON [t7].[ClientId] = ([t8].[Id]) WHERE ([t7].[Email] = LOWER([t1].[Email])) AND ([t8].[ClientTypeId] = @p8) ))))) AND ([t0].[ClientTypeId] = @p9) 

The request works, but it takes 5 minutes.

+1
linq-to-sql query-optimization
source share
1 answer

What db setting are you using? The request may be restructured and simplified a bit, but at first the idea may be to abandon all .ToLower, etc., if you do not use case-sensitive sorting ...

Edit:, you can try changing your query to a bunch of smaller concatenated queries that leave the sql optimizer less creative freedom ... (many or "conditions in a query tend to result in a scan, even if there are covering indexes).

eg:.

 ( from e in dc.Clients join u in dc.ClientUsers on e.Id equals u.ClientId join vc in dc.Clients on new { ClientTypeId = 2, e.VAT } equals new { vc.ClientTypeId, vc.VAT } where e.ClientTypeId == 4 && e.DeleteFlag.Equals("n") && e.VAT != null && e.VAT != "" select e ).Union( from e in dc.Clients join u in dc.ClientUsers on e.Id equals u.ClientId join ec in dc.Clients on new { ClientTypeId = 2, e.Email } equals new { ec.ClientTypeId, ec.Email } where e.ClientTypeId == 4 && e.DeleteFlag.Equals("n") && e.Email != null && e.Email != "" select e ).Union( from e in dc.Clients join u in dc.ClientUsers on e.Id equals u.ClientId join c1u in dc.ClientUsers on e.Email equals new c1u.Email join c1c in dc.Clients on new { ClientTypeId = 2, c1u.ClientId } equals new { c1c.ClientTypeId, ClientId = c1c.Id } where e.ClientTypeId==4 && e.DeleteFlag.Equals("n") && e.Email != null && e.Email != "" select e ).Union( from e in dc.Clients join u in dc.ClientUsers on e.Id equals u.ClientId join c2u in dc.ClientUsers on u.Email equals c2u.Email join c2c in dc.Clients on new { ClientTypeId = 2, c2u.ClientId } equals new { c2c.ClientTypeId, ClientId = c2c.Id } where e.ClientTypeId==4 && e.DeleteFlag.Equals("n") && u.Email != null && u.Email != "" select e ) 
+2
source share

All Articles