更新语句需要永远完成

sai*_*ram 6 sql-server-2008 sql-server t-sql

我有大约 1250000 条记录和 80 列

表结构

CREATE TABLE [dbo].[Table] (
[Column1] [int] IDENTITY(1, 1) NOT FOR REPLICATION NOT NULL, [Column2] [int] NULL, [Column3] [int] NULL, 
[Column4] [int] NULL, [Column5] [int] NULL, [Column6] [int] NULL, [Column7] [int] NULL, [Column8] [int] NULL, 
[Column9] [int] NULL, [Column10] [varchar](20) NULL, [Column11] [datetime] NULL, [Column12] [int] NULL, 
[Column13] [money] NULL, [Column14] [money] NULL, [Column15] [varchar](40) NULL, [Column16] [int] NULL, 
[Column17] [int] NULL, [Column18] [varchar](20) NULL, [Column19] [varchar](50) NULL, [Column20] [int] NULL, 
[Column21] [int] NULL, [Column22] [int] NULL, [Column23] [int] NULL, [Column24] [int] NULL, 
[Column25Date] [datetime] NULL, [Column26] [int] NULL, [Column27] [int] NULL, [Column28] [int] NULL, 
[Column29] [int] NULL, [Column30] [int] NULL, [Column75] [varchar](50) NULL, [Column31] [int] NULL, 
[Column32] [varchar](15) NULL, [Column33] [int] NULL, [Column34] [money] NULL, 
[Column35] [dbo].[T_Boolean2] NOT NULL, [Column36] [money] NULL, [Column37] [money] NULL, 
[Column38] [int] NULL, [Column39] [int] NULL, [Column40] [varchar](255) NULL, [Column41PrintDate] [datetime] NULL, 
[Column42PostDate] [datetime] NULL, [Column43FirstName] [varchar](30) NULL, [Column44LastName] [varchar](30) NULL, 
[Column45Email] [varchar](50) NULL, [Column46PrimaryPhone] [varchar](10) NULL, 
[Column47SecondaryPhone] [varchar](10) NULL, [Column48PrimaryPhoneType] [smallint] NULL, 
[Column49SecondaryPhoneType] [smallint] NULL, [Column50PrimaryPhoneType] [smallint] NULL, 
[Column51SecondaryPhoneType] [smallint] NULL, [Column52EndDate] [datetime] NULL, 
[Column53] [dbo].[T_Boolean2] NOT NULL, [Column54] [int] NULL, [InsertTimeStamp] [datetime] NOT NULL, 
[UpdateTimeStamp] [datetime] NULL, [Column55ID] [int] NULL, [Column56] [int] NULL, [Column57] [int] NULL, 
[Column58] [int] NULL, [Column59] [money] NULL, [Column60] [money] NULL, [Column61] [money] NOT NULL, 
[Column62] [money] NOT NULL, [Column63] [varchar](30) NULL, [Column64] [varchar](30) NULL, 
[Column65] [varchar](10) NULL, [Column66] [varchar](6) NULL, [Column67] [varchar](10) NULL, 
[Column68] [varchar](35) NULL, [Column69Date] [datetime] NULL, [Column70Date] [datetime] NULL, 
[Column71Date] [datetime] NULL, [Column72] [varchar](255) NULL, [Column73PIN] [varchar](6) NULL, 
[Column74Date] [datetime] NULL, [Column76Date] [datetime] NULL, 
CONSTRAINT [XPKColumn1] PRIMARY KEY CLUSTERED (
[Column1] ASC
 ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

它有 2 个更新触发器也可以执行后台计算,当状态改变和其他一些条件时,它将更新同一个表

当我更新一个是它的列,条件正常时,它运行了 1 个多小时,但仍然无法更新记录,所以我被迫终止该语句

Update Table Column5 = 12345 where Column5 = 6789
Run Code Online (Sandbox Code Playgroud)

它必须更新大约 35000 条记录

表确实有正确的索引与此列,我手动更新表的统计信息,但仍然需要太多时间来更新

表有大约 10 个索引

然后我尝试分 2 批更新它更新但花了很长时间

我试图更新同一个表的其他列,更新需要几秒钟

Update Table Column3 = 6789 where Column3 = 12345
Run Code Online (Sandbox Code Playgroud)

我如何快速提高更新语句查询速度并使用上述简单逻辑

请提出任何解决方案,

提前致谢

db2*_*db2 5

如果没有看到触发器的代码,很难确切地说出导致它的原因,但我敢打赌,误用 INSERTED 和 DELETED 虚拟表是罪魁祸首。

INSERTED 和 DELETED 的问题在于它们没有索引。如果您将它们直接连接回基表(或相互连接),则最终可能会出现非常糟糕的性能。

您通常可以通过将两者加载到临时表并为您将加入它们的索引(通常在主键上)创建索引来缓解这种情况。

SELECT *
INTO #i
FROM INSERTED

CREATE CLUSTERED INDEX CX_i ON #i (primary_key)

SELECT *
INTO #d
FROM DELETED

CREATE CLUSTERED INDEX CX_d ON #d (primary_key)
Run Code Online (Sandbox Code Playgroud)

反正就是这样。然后只使用您的临时表,不要触摸 INSERTED 和 DELETED。

请注意,每个会话的临时表名称必须是唯一的。如果您有多个触发器级联,则它们需要使用唯一的表名。如果这成为一个问题,您可能希望改用表变量,因为它们的范围仅限于它们正在运行的触发器/过程,没有名称冲突的风险。(但是,索引表变量的唯一方法是在DECLARE语句中声明聚集主键。)


Up_*_*One 3

您可以通过以较小的组更新表来提高更新操作的性能。

参见示例:

SET rowcount 10000

    Update Table 
      Column3 = 6789 
      where Column3 = 12345

    while @@rowcount>0

    Update Table 
      Column3 = 6789 
      where Column3 = 12345

    END

    SET rowcount 0
Run Code Online (Sandbox Code Playgroud)

上面的代码一次更新 10000 行,循环继续直到 @@rowcount 的值等于 0。这可以确保表不被锁定。

在 SQL Server 中更新大型表时的最佳实践

  • 始终使用WHERE子句来限制要更新的数据
  • 如果表的索引过多,最好在更新时禁用它们,更新后再次启用它们。
  • 不要一次性更新表,而是将其分成组,如上例所示。

另一个补充- 这可能有点复杂,当您拥有大表时,最好按特定字段进行分区,然后将这些分区分布在多个磁盘上。

  • @Mat,这是指 SET ROWCOUNT 而不是 @@ROWCOUNT。我一直避免设置行计数的方法是使用 UPDATE TOP(N) 并且永远不要弄乱行计数。这是在忘记将其重置为 0 一次并想知道为什么只有 x 行受到影响之后。 (3认同)

归档时间:

查看次数:

10787 次

最近记录:

10 年 前