MS SQL - 删除查询花费太多时间

时间:2016-01-30 11:57:48

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

我有以下查询脚本:

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
  • 没有定义索引,因为现在当我要创建新索引时,该查询也会被暂停。

查询执行计划(1): enter image description here

第二部分: enter image description here

以下查询为此提供了一行并显示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

3 个答案:

答案 0 :(得分: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) 

答案 1 :(得分:1)

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

  1. 删除触发器表A.
  2. 批量复制表A至B.
  3. 截断表格A
  4. 启用标识插入。
  5. 从A中插入A,其中A.ID不在ID中以删除。
  6. 禁用标识插入。
  7. 重建索引。
  8. 启用触发器

答案 2 :(得分:0)

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

     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
      )