2017-04-20 62 views
2

我有一個視圖,它查詢大約100多萬行並花費大約10-15分鐘來完成它的執行,我想爲它提供集羣索引,以便它存在於物理架構,並且加載所需的時間更少,但爲了提供羣集索引,存在一些約束條件,即只允許INNER JOIN,並且視圖中不應存在子查詢定義如何用INNER JOIN替換此視圖中存在的LEFT JOIN以及如何從此視圖定義中消除子查詢,以便可以對其應用羣集索引。將集羣索引應用到SQL Server 2012中的視圖

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 
+0

[從這裏開始](https://docs.microsoft.com/en-us/sql/relational-databases/views/create-indexed-views) –

+0

@ ZoharPeled我已閱讀它,我的問題是如何克服這些限制在我的意見定義。 –

+0

沒有什麼奇妙的技巧「爲'Y'開關'X'並且''Z''開關'W'來克服這些限制。如果有,*爲什麼產品不會自動爲你做*?一般情況下,如果原始查詢的構造合理但存在限制,那麼對查詢進行任何理性的重寫都會遇到相同或其他限制。 –

回答

1

我有一個建議。你可以嘗試改變你的查詢,這樣SELECT中的子查詢被放置在CROSS APPLY中嗎?

所以沿着這在WHERE子句線的東西:

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 

然後當然更改選擇列名是這樣的:

, LatestInterventionStatusId.LatestInterventionStatusId 
, LatestInterventionName.LatestInterventionName 

給這個一展身手並讓我知道它是否會有所不同。

0

好吧,你沒有給我一個關於我的問題的答案,但子查詢應該改變。嘗試使用這個,而不是兩個子查詢:

/* 
... 
, 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 
... 
*/