我们有一个表,通过日期字段划分为不同的年份 .

所有这些表都有一个视图(Call)

架构如下:

CREATE TABLE [dbo].[Call_2015](
    [calID] [uniqueidentifier] NOT NULL,
    [calPackageID] [int] NULL,
    [calClientID] [int] NULL,
    [calStartDate] [datetime] NOT NULL,
    [calEndDate] [datetime] NOT NULL,
    [calTimeIn] [char](5) NULL,
    [calTimeOut] [char](5) NULL,
    [calMinutes] [smallint] NULL,
    [calPreferredTimeIn] [char](5) NULL,
    [calPreferredTimeOut] [char](5) NULL,
    [calActualTimeIn] [char](5) NULL,
    [calActualTimeOut] [char](5) NULL,
    [calActualMinutes] [smallint] NULL,
    [calConfirmed] [smallint] NULL,
    [calCarerID] [int] NULL,
    [calRepCarerID] [int] NULL,
    [calOriginalCarerID] [int] NULL,
    [calContractID] [int] NULL,
    [calNeedID] [int] NULL,
    [calMedicationID] [int] NULL,
    [calFrequency] [smallint] NULL,
    [calFromDate] [datetime] NULL,
    [calWeekNo] [smallint] NULL,
    [calAlert] [smallint] NULL,
    [calNoLeave] [smallint] NULL,
    [calTimeCritical] [smallint] NULL,
    [calStatus] [smallint] NULL,
    [calClientAwayReasonID] [int] NULL,
    [calCarerAwayReasonID] [int] NULL,
    [calOutsideShift] [smallint] NULL,
    [calHistoryID] [int] NULL,
    [calInvoiceID] [int] NULL,
    [calWagesheetID] [int] NULL,
    [calReasonID] [int] NULL,
    [calCallConfirmID] [varchar](50) NULL,
    [calCreated] [datetime] NULL,
    [calUpdated] [datetime] NULL,
    [calVariation] [int] NULL,
    [calVariationUserID] [int] NULL,
    [calException] [smallint] NULL,
    [calRetained] [smallint] NULL,
    [calDoubleUpID] [uniqueidentifier] NULL,
    [calDoubleUpOrder] [smallint] NULL,
    [calNeedCount] [smallint] NULL,
    [calNoStay] [smallint] NULL,
    [calCoverCarerID] [int] NULL,
    [calPayAdjustment] [real] NULL,
    [calChargeAdjustment] [real] NULL,
    [calTeamID] [int] NULL,
    [calExpenses] [money] NULL,
    [calMileage] [real] NULL,
    [calOverrideStatus] [smallint] NULL,
    [calLocked] [smallint] NULL,
    [calDriver] [smallint] NULL,
    [calPostcode] [char](10) NULL,
    [calDayCentreID] [int] NULL,
    [calMustHaveCarer] [smallint] NULL,
    [calRoleID] [int] NULL,
    [calUnavailableCarerID] [int] NULL,
    [calClientInformed] [smallint] NULL,
    [calFamilyInformed] [smallint] NULL,
    [calMonthlyDay] [smallint] NULL,
    [calOriginalTimeIn] [char](5) NULL,
    [calLeadCarer] [smallint] NULL,
    [calCallTypeID] [int] NULL,
    [calActualStartDate] [datetime] NULL,
    [calActualEndDate] [datetime] NULL,
    [Table_Year] [int] NOT NULL,
 CONSTRAINT [PK_Call_2015] PRIMARY KEY CLUSTERED 
(
    [Table_Year] ASC,
    [calID] ASC,
    [calStartDate] ASC,
    [calEndDate] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[Call_2015]  WITH CHECK ADD  CONSTRAINT [CK_Call_Year_2015] CHECK  (([Table_Year]=(2015)))
GO

ALTER TABLE [dbo].[Call_2015] CHECK CONSTRAINT [CK_Call_Year_2015]
GO

ALTER TABLE [dbo].[Call_2015]  WITH CHECK ADD  CONSTRAINT [CK_calStartDate_2015] CHECK  (([calStartDate]>=CONVERT([datetime],'01 Jan 2015 00:00:00',(0)) AND [calStartDate]<=CONVERT([datetime],'31 DEC 2015 23:59:59',(0))))
GO

ALTER TABLE [dbo].[Call_2015] CHECK CONSTRAINT [CK_calStartDate_2015]
GO

ALTER TABLE [dbo].[Call_2015] ADD  CONSTRAINT [DF_Call_2015_Table_Year]  DEFAULT ((2015)) FOR [Table_Year]
GO

表的更新如下:

UPDATE Call SET
        calStartDate = CASE 
            WHEN calFrequency = 14 THEN dbo.funDate(@MonthlyDay, MONTH(calStartDate), YEAR(calStartDate))
            WHEN calFrequency IN (15,16) THEN dbo.funMonthlyCallDate(calFrequency, @MonthlyDay, calStartDate)
            ELSE DateAdd(d, @StartDay-1, (calStartDate - datepart(dw,calStartDate)+1)) 
        END,
        calEndDate = CASE 
            WHEN calFrequency = 14 THEN dbo.funDate(@MonthlyDay + @EndDay - @StartDay, MONTH(calStartDate), YEAR(calStartDate))
            WHEN calFrequency IN (15,16) THEN DATEADD(D, @EndDay - @StartDay, dbo.funMonthlyCallDate(calFrequency, @MonthlyDay, calStartDate))
            ELSE DateAdd(d, @StartDay-1+@DayCount, (calStartDate - datepart(dw,calStartDate)+1)) 
        END,
        calTimeIn = @TimeIn,
        calTimeOut = @TimeOut,
        calMinutes = @Minutes,
        calMonthlyDay = @MonthlyDay,
        calClientInformed = Null, 
        calFamilyInformed = Null
    WHERE calPackageID = @PackageID
    AND calClientID = @ClientID
    AND calWeekNo = @WeekNo
    AND (DatePart(dw, calStartDate) = @OriginalDay OR calFrequency IN (14,15,16))
    AND calStartDate BETWEEN @StartDate AND @EndDate
    AND (calInvoiceID = 0 OR calInvoiceID Is Null OR @InvoicesFinalised = 1)
    AND (calWagesheetID = 0 OR calWagesheetID Is Null OR @WagesFinalised = 1)
    AND (calLocked = 0 OR calLocked Is Null)
    AND (Table_Year = YEAR(@StartDate) 
            OR Table_Year =YEAR(@EndDate))

SP将依赖于输入的一批行更新为@StartDate和@EndDate(使用两者之间的calStartDate更新所有行)

然后问题在于执行计划 . 这个操作有巨大的IO成本,我已经把它归结为SQL如何处理更新 .

目前我们有20个表;每年分区 . 每次更新都会导致更新每个表的索引,无论更新操作是否实际触及了表 .

Execution Plan

在本节下面,它继续以完全相同的方式更新视图中的每个表 .

我不明白为什么会这样,因为我在查询文本中指定了Table_Year(表是分区的) . SQL不应该只更新必要的表吗?