【问题标题】:Why SQL DELETE query is not working while using with LIKE Keyword?为什么 SQL DELETE 查询在使用 LIKE 关键字时不起作用?
【发布时间】:2019-07-09 05:52:22
【问题描述】:

我想从我的表中删除一些数据,所以编写一个查询来删除它。所以首先我选择了我想使用这个查询删除的数据,它显示了正确的数据

select * from PATS.Discipline where Code like '%DHA-DIS%'

然后我使用相同的 where 条件编写删除,但它不起作用

DELETE FROM PATS.Discipline WHERE Code LIKE '%DHA-DIS%'

这里我在执行查询时分享一些屏幕截图

这里是一些示例数据

这是最后一次执行结果,我等了 1 分钟最后停止执行

添加了表结构

2019 年 10 月 15 日更新

我今天尝试了同样的场景,我将 5000 条记录导入到表中,并尝试使用相同的查询删除这 5000 条记录,令人惊讶的是它正在工作。我尝试了这两种情况 1.数据没有任何外键存在,它工作正常。这是屏幕截图

  1. 包含外键的数据将显示错误。

这两种情况现在都在工作,我不知道那天 SQL server 发生了什么

【问题讨论】:

  • 不工作是什么意思?是否抛出任何错误
  • 你需要给我们一个可重现的例子来在这里工作。如果第一次选择返回记录,那么第二次删除应该是删除一些东西。
  • 你确定你的命令连接的是同一个数据库吗?
  • 检查表上是否存在触发器以及它们的作用
  • 还有其他应用程序在使用这个表吗?也许在 Visual Studio 的调试会话中?如果另一个应用程序正在使用这个表,那么我可以在这个表上加一个锁,在这种情况下,你的删除语句将不得不等到这个锁被终止

标签: sql sql-server


【解决方案1】:

它应该工作正常,我没有发现查询有任何问题,尝试在新的查询窗口中编写新的查询以确保查询是干净的

对我来说它工作正常并从表中删除测试数据

select * from Discipline
select * from Discipline where Code like '%DHA-DIS%'

DELETE FROM Discipline WHERE Code LIKE '%DHA-DIS%'

(2 row(s) affected)


select * from Discipline where Code like '%DHA-DIS%'

您可以看到上面的查询工作正常,它删除了匹配查询的 2 行。

【讨论】:

【解决方案2】:

可能是表Discipline 被另一个进程锁定了
你可以通过运行这个脚本找到你桌子上的锁

declare @lock table (spid int, dbid int, objId int, indId int, Type char(4), resource nchar(32), Mode char(8), status char(6))
declare @who table (spid int, ecid int, status char(30), loginname char(128), hostname char(128), blk char(5), dbname char(128), cmd char(16), request_id INT)
declare @LockSummary table (loginname varchar(28), DB varchar(128), object varchar(30), ToLevel varchar(20), How_Many int, Xclusive_lock_for_command char(16), spid int, hostname char(128))

insert into @lock exec sp_lock
insert into @who exec sp_who

insert into @LockSummary
select loginname, 
       db_name(dbid) as DB,
       object_name(objID) as object,
       max(mode) as [ToLevel],
       Count(*) as [How Many],
       Max(Case When mode= 'X' Then cmd Else null End) as [Xclusive lock for command],
       l.spid, 
       hostname
from   @lock l 
  join @who w on l.spid = w.spid
where  dbID != db_id('tempdb') 
and    l.status = 'GRANT'
group by dbID, objID, l.spid, hostname, loginname

select * 
from   @LockSummary 
where  object like '%Discipline%'
order by [ToLevel] Desc, [How_Many] Desc, loginname, DB, object

【讨论】:

    【解决方案3】:

    我认为您更关心这里的执行时间,因为它需要很长时间,所以您取消了执行。过去我遇到了同样的问题,我的解决方案是重新启动 SQL Management Studio 并尝试相同的查询,它会正常工作。

    【讨论】:

    • @ganesh,重启 sql server 不是一个好的解决方案。服务器中可能正在运行其他一些进程。
    【解决方案4】:

    1) 您有 5000 行要删除,但这不一定是整个表。表格有多少行?

    2) 您的LIKE 语句需要进行表扫描才能满足。如果有很多行或大列,这将需要很长时间。

    3) 在它使用的表上发布查询计划和统计信息。

    4) 如果您取消delete,那么数据库将回滚。这就是为什么你看到它什么都不做。

    【讨论】:

    • 即使使用表扫描也不应该花那么长时间,因为表中只有 5000 行。我的猜测是另一个进程在桌子上锁了
    【解决方案5】:

    您是否在编辑模式下尝试过相同的查询。 你可以这样做

    1. 右键单击 Pats.Discipline 表。
    2. 选择编辑前 200...行
    3. Ctrl + 3 编辑查询。
    4. 将查询替换为select * from Discipline where Code like '%DHA-DIS%'
    5. 如下图所示,单击顶部的第一个单元格以选择所有行
    6. 点击删除按钮

    如果执行时间过长,请尝试将您的查询更改为类似的内容

    从 Discipline 中选择前 1000 个 *,其中 Code like '%DHA-DIS%'

    如果成功则重复该步骤

    【讨论】:

      【解决方案6】:

      有两件事可能会减慢您的删除速度

      1. 您对引用 Pats.Discipline 表中的 PK 的外键进行了级联删除。您可以通过运行以下查询来检查您是否有任何启用了级联删除的键。
          select * from sys.foreign_keys where delete_referential_action > 0
      
      1. Pats.Discipline 表的主键在具有大量行的其他表中用作外键。在 Discipline 表中删除具有这些字段的记录将触发对引用此键的所有表的引用完整性检查,并且根据某些因素,这可能是一个漫长的过程。 如果您知道此次删除没有违反参照完整性,您可以删除外键,然后运行您的删除命令,然后重新创建外键。

      【讨论】:

      • 我也会检查的。
      【解决方案7】:

      注意:收回

      如果可能的话Alter PATSDiscipline这个,

      ID int PK
      Code varchar(20)
      Name varchar(50)
      CreatedBY varchar(50) or even better INT
      CreatedDate Datetime2(0)
      UpdatedBY varchar(50) or even better INT
      UpdatedDate Datetime2(0)
      

      或者改变任何可能的列。

      CreatedBY 可以通过首先手动加入关注表来转换为INT。 然后更正代码。

      我不是在讨论这一点,Code LIKE '%DHA-DIS%' is NON SARGable。 或者为什么你不应该使用 . 以及代码列是否应为NON Clustered Index

      更改表设计将在各个方面为您提供帮助,无论是 Select 查询还是 DML operation 并且永远如此。

      您也可以这样做

      Select Resultset 放入临时表中,然后加入并删除

      create table #temp (id uniqueidentifier not null primary key)
      
      insert into #temp 
      select id from PATS.Discipline where Code like '%DHA-DIS%'
      
      delete from PATS.Discipline
      where exists(select 1 from #temp where #temp.id=PATS.Discipline.id )
      

      你可以两步走

      如果删除数据为百万,则可以使用分页,

      DECLARE @TopSize INT = 10000
      DECLARE @BatchSize INT = 10000
      DECLARE @MaxLimit INT = 1
      DECLARE @RowCount INT = 0
      
      BEGIN TRY
          WHILE (@TopSize <= @MaxLimit)
          BEGIN
      
      
          delete TOP (@TopSize) from PATS.Discipline
          where exists(select 1 from #temp where #temp.id=PATS.Discipline.id )
      
      
              SET @RowCount = @@RowCount
      
              --PRINT @TopSize
              IF (
                      @RowCount = 0
                      OR @RowCount IS NULL
                      )
                  BREAK;
              ELSE
                  SET @TopSize = @TopSize + @BatchSize
          END
      END TRY
      
      BEGIN CATCH
          --catch error
      END CATCH
      

      【讨论】:

        【解决方案8】:

        这可能不是 LIKE 关键字的问题。 SELECT 似乎返回了很多匹配的行 - 我认为相对较快(?) - 所以问题是“什么是慢的(或阻止)DELETE?”试试

        DELETE TOP 1 FROM PATS.Discipline WHERE Code LIKE '%DHA-DIS%'
        

        如果可行,请尝试TOP 10/100...

        一个有根据的猜测说它很慢,因为重新索引和/或跨表关系(外键约束)和/或只是建立了一个非常大的事务。

        如何加快速度?在已经发布的答案中有很多很好的建议,我也建议看看这个:How to efficiently delete rows while NOT using Truncate Table in a 500,000+ rows table

        【讨论】:

        • 它是这样工作的,问题是它没有删除批量数据
        • 您是否尝试删除前 100 名?如果它有效,那么我发布的链接中的讨论解释了为什么要删除批量,你应该用更小的“块”来做。有一些如何巧妙地做到这一点的例子。 DELETE 以事务方式执行,即数据库在提交之前(使结果最终)在事务日志文件中写入其“意图”(它将要做的一切)(以便在出现问题时可以撤消)。在没有其他证据(例如锁定)的情况下,这可能是您的 DELETE 运行很长时间的原因。谷歌“sql 删除成本”了解更多信息。
        • 不客气。如果您的问题已得到解答,请标记最佳答案。如果没有,但您自己找到了解决方案,请发布。
        【解决方案9】:

        其他所有我认为您最初使用的代码没有任何问题,尽管在删除查询上使用 like 语句会影响性能。如果我知道我只删除了几千行,我会采用 CTE 方法并将其加入到源表中:

        ;With DeleteCTE as 
        (
        
        select 
            [ID],
            Code
        from Discipline 
            where Code like '%DHA-DIS%'
        )
        Delete
        from Discipline D 
        Inner Join
            DeleteCTE DC 
                on DC.ID = D.ID
        

        【讨论】:

          【解决方案10】:

          此答案基于我的个人经验。

          您将 uniqueidentifier 存储为表的 ID 并使其成为主聚集键。由于重新索引表,删除这样数量的行需要时间。所以,我会建议 -

          1. 删除主键索引
          2. 执行删除语句
          3. 重新添加主键索引

          它在类似的情况下帮助了我。 为什么?因为在这个策略中,该表的索引只被操作了两次。虽然删除表的重新索引不会发生。因此,您将看到执行删除的显着改进。

          所以,你的查询应该是这样的-

          ALTER TABLE PATS.Discipline DROP CONSTRAINT [PK_Discipline]
          GO
          DELETE FROM PATS.Discipline WHERE Code LIKE '%DHA-DIS%'
          GO
          ALTER TABLE PATS.Discipline DROP CONSTRAINT [PK_Discipline] PRIMARY KEY CLUSTERED
          GO
          

          注意:这种删除策略应该只适用于表有很多索引或者主键是uniqueidentifier并且你试图从那个表中删除更多行的情况。但在正常情况下,应该应用相同的旧删除查询。

          【讨论】:

            【解决方案11】:

            您使用的查询没有问题。

            可能有几个原因。可能是网线断开了,执行过程中数据库可能下线了,可能是电源故障,或者由于另一个事务导致对表的访问被锁定等

            当您的查询失败时,有时甚至需要超过 1 分钟,对吗?但是当它成功时,执行速度非常快。查询失败时,一定有其他人通过网络访问该表。

            当处理像 5000 这样的大量数据时,您可以使用添加了事务块的存储过程。

            【讨论】:

              猜你喜欢
              • 2013-02-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-08-21
              • 1970-01-01
              • 1970-01-01
              • 2011-10-02
              • 2015-05-25
              相关资源
              最近更新 更多