declare @TopX int = 1000
declare @stores Table (Store varchar(5), LastDate datetime, LastId int, RangeEnd datetime)
insert into @stores
select *
from (select SourceStore, '2014-01-01' as i, null as ii, '2014-01-08' as iii
from StoreConfig.dbo.Version
group by SourceStore
) t
where (ABS(CAST((BINARY_CHECKSUM(*) * RAND()) as int)) % 100) < 50
IF OBJECT_ID('tempdb..#agreements') IS NOT NULL
DROP TABLE #agreements
IF OBJECT_ID('tempdb..#stores') IS NOT NULL
DROP TABLE #stores
select Store,
isnull(LastDate, '1899-01-01') StartDate,
isnull(LastId, -1) LastId,
isnull(RangeEnd, getdate()) RangeEnd
into #stores
from @stores
update #stores set StartDate = '2015-07-01', RangeEnd='2015-07-08'
-- THIS IS NOT FAST.. :(
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--grab the @TopX agreements from primary customers
--note: only grabbing the columns in our index to prevent RID lookups
--on every agreement before we sort and take a relatively tiny subset
select top 1000
a.SourceStore
,a.AgreementId
,isnull(a.ModifiedDate, a.CreatedDate) as ModifiedDate
,ca.CustomerId
from #stores s
inner join StoreOps.POSREPL3Agreement.Agreement a on a.SourceStore = s.Store
inner join StoreOps.Customer.CustomerAgreement ca on ca.SourceStore = a.SourceStore
and ca.AgreementId = a.AgreementId
and ca.IsPrimary = 1
where ( (a.ModifiedDate between s.StartDate and s.RangeEnd)
or ( a.ModifiedDate is null
and a.CreatedDate between s.StartDate and s.RangeEnd)
)
and ( isnull(a.ModifiedDate, a.CreatedDate) > s.StartDate
or a.AgreementId > s.LastId
)
order by isnull(a.ModifiedDate, a.CreatedDate), a.AgreementId
我们对于表[Customer].[CustomerAgreement]有以下索引:
CREATE NONCLUSTERED INDEX [IX_CustomerAgreement_SourceStore_AgreementId]
ON [Customer].[CustomerAgreement]
([SourceStore] ASC, [AgreementId] ASC, [IsPrimary] ASC)
INCLUDE ([CustomerId])
ON [PRIMARY]
GO
这是[POSREPL3Agreement].[Agreement]表的索引:
CREATE NONCLUSTERED INDEX [IX_Agreement_SourceStore_ModifiedDate]
ON [POSREPL3Agreement].[Agreement]
([SourceStore] ASC, [ModifiedDate] ASC, [CreatedDate] ASC)
INCLUDE ([AgreementId])
ON [PRIMARY]
GO
如果我们移除WHERE子句,索引会按预期工作,并且我们可以从两个表中看到1000条记录,但是当我们添加列出的WHERE子句[Customer].[CustomerAgreement]时,[CustomerAgreement]估计了所有记录,而不仅仅是1000条。
我们如何改进WHERE子句或索引,使得[Agreement]表与[CustomerAgreement]表对齐,以便[CustomerAgreement]下的估计行数不是所有记录?
表定义
CREATE TABLE [Customer].[CustomerAgreement](
[CustomerAgreementId] [int] NOT NULL,
[CustomerId] [int] NOT NULL,
[AgreementId] [int] NOT NULL,
[IsPrimary] [bit] NOT NULL,
[Store] [varchar](5) NOT NULL,
[SourceStore] [varchar](5) NOT NULL,
[RowGUID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Repl_ID] [tinyint] NOT NULL,
CONSTRAINT [PK_Customer_CustomerAgreementID_SourceStore] PRIMARY KEY NONCLUSTERED
(
[CustomerAgreementId] ASC,
[SourceStore] ASC,
[Repl_ID] ASC,
[RowGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [POSREPL3Agreement].[Agreement](
[AgreementId] [int] NOT NULL,
[QuoteId] [int] NULL,
[AgreementNumber] [varchar](11) NOT NULL,
[AgreementStatusId] [tinyint] NOT NULL,
[AgreementPrinted] [bit] NOT NULL,
[IsNewPOSCreated] [bit] NOT NULL,
[LeaseFrequencyId] [tinyint] NOT NULL,
[DeferredLateFeeAmount] [decimal](8, 2) NOT NULL,
[InHomeVisitFeeAmount] [decimal](8, 2) NOT NULL,
[IsASPTaxable] [bit] NOT NULL,
[ServicePlusRate] [decimal](7, 5) NOT NULL,
[ServicePlusFloor] [decimal](5, 2) NOT NULL,
[TaxRatePercentage] [decimal](7, 5) NOT NULL,
[IgnoreTaxRateChange] [bit] NOT NULL,
[Balance] [decimal](8, 2) NOT NULL,
[AmountPaidToDate] [decimal](10, 2) NOT NULL,
[Deposit] [decimal](8, 2) NOT NULL,
[DeliveryFee] [decimal](8, 2) NOT NULL,
[StartDate] [datetime] NOT NULL,
[DueDay] [int] NOT NULL,
[DueDayTypeId] [tinyint] NULL,
[PaidThroughDate] [datetime] NOT NULL,
[PayOutDate] [datetime] NOT NULL,
[FinalDate] [datetime] NULL,
[IsNSFOutstanding] [bit] NOT NULL,
[LeadSourceId] [tinyint] NOT NULL,
[AgreementTypeId] [tinyint] NOT NULL,
[AcquisitionAgreementTypeId] [tinyint] NULL,
[SameAsCashDuration] [int] NOT NULL,
[SameAsCashDurationType] [int] NOT NULL,
[MinimumPercentageOfCashPriceForFinalPayment] [decimal](3, 2) NOT NULL,
[EarlyPayoutLeaseAmountRate] [decimal](3, 2) NOT NULL,
[EarlyPayout] [decimal](10, 2) NULL,
[FinalPaymentAdditionalFee] [decimal](8, 2) NOT NULL,
[FinalPaymentProrateAmount] [decimal](10, 2) NOT NULL,
[CreditedAssociateId] [int] NULL,
[NonRenewalGracePeriod] [int] NOT NULL,
[LastAgreementTransactionId] [int] NULL,
[CanPayout] [bit] NOT NULL,
[IsServicePlusIncludedInPayout] [bit] NOT NULL,
[IsProrateEnabled] [bit] NOT NULL,
[AgreementDocument] [varbinary](max) NULL,
[CreatedDate] [datetime] NOT NULL,
[CreatedBy] [int] NULL,
[ModifiedDate] [datetime] NULL,
[ModifiedBy] [int] NULL,
[Store] [varchar](5) NOT NULL,
[SourceStore] [varchar](5) NOT NULL,
[RowGUID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[Repl_ID] [tinyint] NOT NULL,
[ECommerceDeliveredDate] [datetime] NULL,
[DDEStatusId] [tinyint] NULL,
[DDEAmount] [decimal](8, 2) NULL,
[OrderMethodTypeId] [int] NULL,
[SemiMonthlyUpcharge] [decimal](8, 2) NULL,
[DefaultNonRenewalFee] [decimal](8, 2) NULL,
[DefaultInHomeVisitFee] [decimal](8, 2) NULL,
[NonRenewalSemiMonthlyFee] [decimal](8, 2) NULL,
[NonRenewalSemiMonthlyFeeGracePeriod] [int] NULL,
[NonRenewalFeeTypeId] [int] NULL,
[NonRenewalSemiMonthlyRate] [decimal](8, 4) NULL,
[NonRenewalMonthlyRate] [decimal](8, 4) NULL,
[NonRenewalWeeklyFeeGracePeriod] [int] NULL,
[NonRenewalWeeklyRate] [decimal](8, 4) NULL,
[NonRenewalWeeklyFee] [decimal](8, 2) NULL,
[DefaultNSFFee] [decimal](8, 2) NULL,
[WeeklyUpcharge] [decimal](8, 2) NULL,
[IsInHomeFeeEnabled] [bit] NULL,
[CanChargeInHomeFeeAndNonRenewalFeeInSamePeriod] [bit] NULL,
[ExtensionBalance] [decimal](8, 2) NOT NULL,
CONSTRAINT [PK_Agreement_AgreementID_SourceStore] PRIMARY KEY NONCLUSTERED
(
[AgreementId] ASC,
[SourceStore] ASC,
[Repl_ID] ASC,
[RowGUID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
执行计划
点击这里下载Showplan XML(pastebin)
