我正在使用 SQL Server 2019 并面临一个问题,即在进行更新时,仅 162 行需要 20 秒。
Update FT SET
ft.ValueName=avo.name
FROM #package FT
inner join parts.Nop_PackageAttribute PA with(nolock)
on PA.PackageID=ft.PackageID
and PA.[Key]=FT.ZfeatureId
inner join Nop_AcceptedValuesOption AVO with(nolock)
ON convert(varchar(20),AVO.AcceptedValuesOptionID)=PA.Value
where FT.AcceptedValueID is not null
脚本示例
create table #package
(
id int PRIMARY KEY IDENTITY(1,1),
ZfeatureId INT NULL,
AcceptedValueID INT NULL,
PackageID INT NULL,
ValueName NVARCHAR(2000) default ''
)
我在#package 表上的索引
create nonclustered index IDX_PackageID on #package(PackageID) include (ZfeatureId,AcceptedValueID , ValueName)
create index acceptedvaluesidpackage_idx on #package(AcceptedValueID)
包属性表
ALTER TABLE [Parts].[Nop_PackageAttribute] ADD CONSTRAINT [PK_Nop_PackageAttribute] PRIMARY KEY CLUSTERED
(
[PackageAttributeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED INDEX [_dta_index_Nop_PackageAttribute_8_578153155__K2_K1_K3_4] ON [Parts].[Nop_PackageAttribute]
(
[PackageID] ASC,
[PackageAttributeID] ASC,
[Key] ASC
)
INCLUDE ( [Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
CREATE NONCLUSTERED INDEX [IDX_Key] ON [Parts].[Nop_PackageAttribute]
(
[Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
CREATE NONCLUSTERED INDEX [IDX_PakageID] ON [Parts].[Nop_PackageAttribute]
(
[PackageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED INDEX [IX_Nop_PackageAttribute_Key] ON [Parts].[Nop_PackageAttribute]
(
[Key] ASC
)
INCLUDE ( [PackageID],
[Value]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
CREATE TABLE [Parts].[Nop_PackageAttribute](
[PackageAttributeID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[PackageID] [int] NOT NULL,
[Key] [int] NOT NULL,
[Value] [nvarchar](max) NOT NULL,
[CreatedDate] [datetime] NULL,
[CreatedBy] [int] NULL,
[ModifiedDate] [datetime] NULL,
[ModifiedBy] [int] NULL,
[DeletedDate] [datetime] NULL,
[DeletedBy] [int] NULL,
CONSTRAINT [PK_Nop_PackageAttribute] PRIMARY KEY CLUSTERED
(
[PackageAttributeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
) ON [Customer] TEXTIMAGE_ON [PRIMARY]
Nop_AcceptedValuesOption 表
ALTER TABLE [dbo].[Nop_AcceptedValuesOption] ADD CONSTRAINT [PK_Nop_AcceptedValuesOption] PRIMARY KEY CLUSTERED
(
[AcceptedValuesOptionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED COLUMNSTORE INDEX [_dta_index_Nop_AcceptedValuesOption_5_1669580986__col__] ON [dbo].[Nop_AcceptedValuesOption]
(
[AcceptedValuesOptionID],
[AcceptedValuesID],
[Name],
[DisplayOrder],
[Description],
[CreatedDate],
[CreatedBy],
[ModifiedDate],
[ModifiedBy],
[DeletedDate],
[DeletedBy],
[Is_Split],
[AcceptedValuesOption_Value],
[AcceptedValuesOption_Unit]
)WITH (DROP_EXISTING = OFF) ON [Customer]
CREATE NONCLUSTERED INDEX [_dta_index_Nop_AcceptedValuesOption_8_1074154922__K1_3] ON [dbo].[Nop_AcceptedValuesOption]
(
[AcceptedValuesOptionID] ASC
)
INCLUDE ( [Name]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED INDEX [_dta_index_Nop_AcceptedValuesOption_8_1074154922__K2_K4_1_3] ON [dbo].[Nop_AcceptedValuesOption]
(
[AcceptedValuesID] ASC,
[DisplayOrder] ASC
)
INCLUDE ( [AcceptedValuesOptionID],
[Name]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20160824-070515] ON [dbo].[Nop_AcceptedValuesOption]
(
[AcceptedValuesID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE NONCLUSTERED INDEX [NonClusteredIndex-20160829-015901] ON [dbo].[Nop_AcceptedValuesOption]
(
[Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
GO
CREATE TABLE [dbo].[Nop_AcceptedValuesOption](
[AcceptedValuesOptionID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[AcceptedValuesID] [int] NOT NULL,
[Name] [nvarchar](500) NOT NULL,
[DisplayOrder] [int] NOT NULL,
[Description] [varchar](250) NULL,
[CreatedDate] [datetime] NULL,
[CreatedBy] [int] NULL,
[ModifiedDate] [datetime] NULL,
[ModifiedBy] [int] NULL,
[DeletedDate] [datetime] NULL,
[DeletedBy] [int] NULL,
[Is_Split] [int] NULL,
[AcceptedValuesOption_Value] [float] NULL,
[AcceptedValuesOption_Unit] [nvarchar](20) NULL,
[IsDeleted] [bit] NULL,
CONSTRAINT [PK_Nop_AcceptedValuesOption] PRIMARY KEY CLUSTERED
(
[AcceptedValuesOptionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Customer]
) ON [Customer]
GO
SET ANSI_PADDING ON
GO
ALTER TABLE [dbo].[Nop_AcceptedValuesOption] ADD CONSTRAINT [DF_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO
ALTER TABLE [dbo].[Nop_AcceptedValuesOption] CHECK CONSTRAINT [FK_Nop_AcceptedValuesOption_Nop_AcceptedValues]
GO
那么,如何增强更新语句更快呢?
添加到布伦丹的答案,交换这个转换
至
并且您应该能够用 162 个索引查找替换非聚集列存储扫描。如果您没有获得嵌套循环计划,请尝试
inner loop join
.您应该避免在
WHERE
子句中围绕列包装函数。通过环绕 aCONVERT
,AcceptedValuesOptionID
SQL Server 必须在表中的每一行上运行该函数,然后才能知道值是否等于PA.Value
。话虽如此,这很可能是您
WHERE
条款中导致您的缓慢的部分。我看到发生了两件事。
看看是否有另一种方法可以连接到该表,其中连接两侧的列是相同的数据类型。
另一种选择可能是更改上的数据类型
AVO.AcceptedValuesOptionID
。但是,更改现有表中的数据类型是有风险的。您需要确保在此过程中不会破坏其他查询。此外,如果您知道始终
PA.value
可以包含 INT 数据的特定场景,您可以考虑创建一个临时表并将这些行子集插入到临时表中。您将使用该列作为 INT 数据类型创建此临时表,然后在原始联接中使用临时表,而不是基表。这看起来像我过去被咬过的一个问题,我仍然有伤疤。
尝试这个:
convert(nvarchar(20),AVO.AcceptedValuesOptionID)=PA.Value
事情是这样的,PA.Value 是n vachar,但是您将 AVO.AcceptedValuesOptionID 转换为 varchar。这会导致 SQL Server 在比较之前首先将每个 PA.Value 转换为 varchar。这是一个昂贵的转换,因为它需要考虑非 ASCII 字符的各种等效规则。
(其他答案中的建议可能仍会进一步提高性能,但我强烈怀疑这是罪魁祸首。)