Reputation: 81
I have a view which queries around 1+ million rows and takes around 10-15 minutes to finish its execution,I want to provide cluster indexing to it so that it exists in physical schema and takes less time to load, but there are a number of constraints in order to provide cluster indexing i.e. only INNER JOIN are allowed and No subqueries should be present in views defination how do I replace the LEFT JOIN present in this view with INNER JOIN and how do I eliminate subqueries from this views defination so that cluster indexing can be applied to it.
CREATE view [dbo].[FTM_ProfileDetailsView] with SCHEMABINDING as
select FTM.Id
, FTM.EmployeeId
, FTM.CustomerId
, FTM.AbsenceFirstDate
, FTM.BackgroundHistory
, FTM.BackgroundHistoryComments
, FTM.IsEmployeeAbsent,FTM.ServiceId
, Case When isnull(FTM.IsSelfManagement,'')='' THEN cast(0 as bit) ELSE FTM.IsSelfManagement END as IsSelfManagement
, PR.ServiceLineId,FTM.ProfileId,PR.StatusId,Status.Status as StatusName
, PR.ReasonID
, PR.ModifiedDate
, PR.WithdrawnReason
, PR.CreatedBy
, PR.CreatedDate
, PR.IsActive
, mgrs.usernames as LineManagers
, cust.CustomerName
, ltrim(rtrim( emp.EmployeeTitle+' '+ emp.FirstName+' '+ emp.Surname)) as EmployeeFullName
, FTM.ProfileManagerId
, FTM.IsProfileManagement
, AM.MonitoringChecks
, AM.Frequency
, AM.ProfileManagerNotes
, AM.TaskDateAndTime
, FTM.ProfileManagementCriteriaId
,cast(case when PR.StatusId = 13 then 1 else 0 end as bit) as IsActiveMonitoring
, CustServ.CustomerServiceName
, BU.Name as BusinessUnit
, emp.DASID
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
, (select top 1
StatusId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc) as LatestInterventionStatusId
, (select name from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc))
as LatestInterventionName from FTM_Profile FTM
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
INNER JOIN dbo.PR_Profile PR on PR.Profileid=FTM.ProfileId
LEFT JOIN dbo.BusinessUnit BU on BU.Id=PR.BUId
LEFT JOIN dbo.PR_dv_Status [Status] on [Status].Id = PR.StatusId
LEFT JOIN dbo.CM_ActiveMonitoringDetails AM on AM.ProfileId = PR.Profileid
LEFT JOIN dbo.FTM_CustomerServiceMapping CustServ on CustServ.ServiceId = FTM.ServiceId and CustServ.CustomerId = FTM.CustomerId
LEFT JOIN dbo.contact con on con.Id = emp.ContactID
LEFT JOIN dbo.address addr on addr.Id = con.HomeAddressId
LEFT JOIN dbo.contactinfo coninfo on coninfo.Id = con.ContactInfoId
Upvotes: 2
Views: 67
Reputation: 2191
Ok, you didn't give me an answer on my question, but the subqueries should be changed. Try to use this instead the two subqueries:
/*
...
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
*/
, p.StatusId as LatestInterventionStatusId
, p.name as LatestInterventionName
from FTM_Profile FTM
OUTER APPLY (
select TOP 1 Intr.name, ProfileInt.StatusId
from dbo.PR_Profileintervention ProfileInt
LEFT JOIN dbo.FTM_Intervention Intr ON Intr.Id = ProfileInt.InterventionId
where ProfileInt.ProfileId = FTM.Profileid
order by ProfileInt.Id desc
) p
/*
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
...
*/
Upvotes: 0
Reputation: 583
I have a suggestion. Can you try and change your query so the sub -queries in the SELECT are placed in CROSS APPLYs?
So something along the lines of this in your WHERE clause:
CROSS APPLY (
select top 1 StatusId AS LatestInterventionStatusId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc
) LatestInterventionStatusId
CROSS APPLY (
select name AS LatestInterventionName
from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc)
)LatestInterventionName
And then of course change the column names in the SELECT to something like this:
, LatestInterventionStatusId.LatestInterventionStatusId
, LatestInterventionName.LatestInterventionName
Give this a go and let me know if it makes a different.
Upvotes: 1