【问题标题】:MS SQL - Delete query taking too much timeMS SQL - 删除查询花费太多时间
【发布时间】:2016-01-31 05:03:51
【问题描述】:

我有以下查询脚本:

declare @tblSectionsList table
(
    SectionID int,
    SectionCode varchar(255)
)
--assume @tblSectionsList has 50 sections- rows

DELETE 
    td
from 
    [dbo].[InventoryDocumentDetails] td
    inner join [dbo].InventoryDocuments th 
          on th.Id = td.InventoryDocumentDetail_InventoryDocument
    inner join @tblSectionsList ts 
          on ts.SectionID = th.InventoryDocument_Section

这个脚本包含三个表,其中@tblSectionsList是一个临时表,它可能包含50条记录。然后我在与InventoryDocuments 表的连接条件中使用此表,然后进一步连接到InventoryDocumentDetails 表。所有连接都基于 INT 外键。

在周末,我将此查询放在服务器上,即使在 2 天 4 小时后它仍在运行......任何人都可以告诉我我是否做错了什么。或者有什么想法可以提高它的性能?甚至不知道还要多少时间才能给我结果。

在此之前,我还尝试使用以下脚本在 InventoryDocumentDetails 表上创建索引:

CREATE NONCLUSTERED INDEX IX_InventoryDocumentDetails_InventoryDocument
    ON dbo.InventoryDocumentDetails (InventoryDocumentDetail_InventoryDocument);

但是这个脚本也需要一天多的时间并且没有完成所以我取消了这个查询。

附加信息:

  • 我正在使用 MS SQL 2008 R2。
  • InventoryDocuments 表包含 2108137 行,主键为“Id”。
  • InventoryDocumentDetails 表包含 25055158 行,主键为“Id”。
  • 两个表都定义了主键。
  • CUP - Intel Xeon - 32 GB RAM
  • 没有定义索引,因为现在当我要创建新索引时,该查询也会暂停。

查询执行计划(一):

第二部分:

以下查询为此提供一行并显示 status='suspended' 和 wait_type='LCK_M_IX'

SELECT r.session_id as spid, r.[status], r.command, t.[text], OBJECT_NAME(t.objectid, t.[dbid]) as object, r.logical_reads, r.blocking_session_id as blocked, r.wait_type, s.host_name, s.host_process_id, s.program_name, r.start_time
FROM sys.dm_exec_requests AS r LEFT OUTER JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id OUTER APPLY sys.dm_exec_sql_text(r.[sql_handle]) AS t
WHERE r.session_id <> @@SPID AND r.session_id > 50

【问题讨论】:

  • 您应该在问题中包含查询计划。另外,您是否检查过没有阻塞导致删除等待?
  • 下一个发布 RAM 的家伙 - 但不是在谈论数据库大小、查询计划和 DISC SUBSYSTEMS。服务器很可能在完全不合适的慢速硬盘上运行。请查询计划。和光盘布局。
  • 它成功删除了其他查询,比如1分钟内从另一个表中删除了1000万行。数据库大小约为 15 GB。
  • 快速说明:"@tblSectionsList 是一个临时表" 不正确。 @tblSectionsList 是一个 TABLE 变量,TABLE 变量和临时表之间存在相当大的差异。
  • 我在 InventoryDocumentDetailExtensions 上看到聚集索引扫描...这是在做什么?

标签: sql-server tsql sql-server-2008-r2


【解决方案1】:

将Inner Join 更改为EXISTS 会发生什么

DELETE td
FROM   [dbo].[InventoryDocumentDetails] td
WHERE  EXISTS (SELECT 1
               FROM   [dbo].InventoryDocuments th
               WHERE  EXISTS (SELECT 1
                              FROM   @tblSectionsList ts
                              WHERE  ts.SectionID = th.InventoryDocument_Section)
                      AND th.Id = td.InventoryDocumentDetail_InventoryDocument) 

【讨论】:

  • 非常感谢@VR46,它有效。只需 5 分钟即可完成查询。
【解决方案2】:

有时截断表并重新导入要保留的记录在时间上更有效。与插入相比,对大表的删除操作非常慢。当然,这只是一个选项,如果你可以让你的桌子离线。此外,仅当您的日志记录设置为简单时才执行此操作。

  1. 删除触发器表 A。
  2. 将表 A 批量复制到 B。
  3. 截断表 A
  4. 启用身份插入。
  5. 从 B 中插入 A.ID 不在要删除的 ID 中。
  6. 禁用身份插入。
  7. 重建索引。
  8. 启用触发器

【讨论】:

  • 感谢@Irb 提供另一个技巧。下面(用户=VR46)的答案已经完成了这项工作,但这在困难时期也是可行的建议。
【解决方案3】:

尝试如下。至少它可能会给你一些想法。

     DELETE FROM [DBO].[INVENTORYDOCUMENTDETAILS] WHERE INVENTORYDOCUMENTDETAILS_PK IN (
     (SELECT INVENTORYDOCUMENTDETAILS_PK FROM
     [DBO].[INVENTORYDOCUMENTDETAILS] TD
     INNER JOIN [DBO].INVENTORYDOCUMENTS TH ON TH.ID = TD.INVENTORYDOCUMENTDETAIL_INVENTORYDOCUMENT
     INNER JOIN @TBLSECTIONSLIST TS ON TS.SECTIONID = TH.INVENTORYDOCUMENT_SECTION
      )

【讨论】:

    猜你喜欢
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 2018-01-08
    • 2019-11-14
    • 2012-09-03
    • 2013-07-11
    相关资源
    最近更新 更多