【问题标题】:SQL Server DELETE and SELECT Behave Differently with Same WHERE ClauseSQL Server DELETE 和 SELECT 在相同的 WHERE 子句中表现不同
【发布时间】:2011-11-14 21:59:24
【问题描述】:

我有一个表,该表由每日计划作业填充,该作业删除最后 7 天的数据,然后使用来自另一个源(大型机)的最近 7 天的数据重新填充。

最近,用户报告了许多重复数据,可追溯到 2011 年 10 月初。...数量级为数十万行。

我注意到为每个作业运行的删除有奇怪的行为:

DELETE FROM fm104d 
 WHERE location = '18'
   AND (CONVERT(datetime,CASE WHEN ISDATE(pull_date)=0 THEN '19000101' 
                 ELSE pull_date END)) >  DATEADD(day, -7, getdate())

以上返回“(0行受影响)”。

当我在用 SELECT * 替换 DELETE 后运行上述命令时,我得到 32,000 多行作为回报。

为什么 SELECT 和 DELETE 的行为会有所不同?

更新

这是实际的执行计划:

http://pastie.org/2869202

【问题讨论】:

  • 调查这条线AND (CONVERT(datetime,CASE WHEN ISDATE(pull_date)=0 THEN '19000101' ELSE pull_date END)) > DATEADD(day, -7, getdate())
  • 桌子上有任何触发器吗?
  • 您是否在同一登录名下运行DELETESELECT?如果不是,请检查两个登录是否具有相同的 dateformat 设置(默认语言)
  • 只是为了澄清当你写“上面返回零行”时,你的意思是消息阅读(0 row(s) affected)
  • 你能发布实际执行计划的 XML 版本吗?

标签: sql sql-server


【解决方案1】:

你不会相信的。实际上我没有这样做,因为它几乎没有逻辑意义,但最终,有效的解决方案......是添加一个索引。

这要归功于我当地的 DBA “是否考虑过添加索引?我只是做了测试,果然它可以工作”。

这是添加的索引:

CREATE  INDEX ixDBO_fir104d__SOURCE_LOCATION__Include
ON [dbo].[fir104d] ([SOURCE_LOCATION])
INCLUDE ([Transaction_Date],[PULL_DATE])
GO

我让作业按计划运行,果然,一切照旧。

我的猜测是解释计划中有一些内容表明它没有使用索引/错误的索引,但我的开发人员无法理解这种详细程度。

感谢大家花费的时间和精力。

更新

从另一个开发人员那里收到消息,该表中的数据还损坏到需要“DBA 参与数小时才能解决”的程度,并且开发人员必须执行一些其他数据修复(读取:数据文件重新加载) .

归根结底,虽然考虑到计划作业的运行方式,添加索引可能是一件好事,但显然还有更多的故事!

【讨论】:

  • 你说得对,我不相信。 select找到没有索引的记录但是delete找不到?惊人的。 +50 以便我以后遇到同样的事情时可以参考这个问题。
  • 我想知道如果有一个主键可以防止这个问题摆在首位?
  • 或者可能是因为索引已损坏并且在添加时被重新构建..(我们永远不会真正知道:D)
  • @MatthewPK 可能!如果我必须将系统作为一个整体来描述,我会想到“纸牌屋”。
  • @xQbert 有趣的事情。它真正与 DBA 一起使用的方式是他添加索引、测试、删除、通知我“嘿,索引!”,然后在我正式请求后重新添加。在最后添加索引之前观察到的问题。
【解决方案2】:

试试这个:

DELETE FROM fm104d  where fm104d.id in 
(
select  id from fm104d 
 WHERE location = '18'
   AND (CONVERT(datetime,CASE WHEN ISDATE(pull_date)=0 THEN '19000101' 
                 ELSE pull_date END)) >  DATEADD(day, -7, getdate())
)aaa

如果删除了就回复

附言: 这不是解决方案,但会导致决策。

【讨论】:

  • 谢谢,但不完全是。此表上没有 ID 列(是的,系统很糟糕)。此外,性能/内存也是一个问题。
  • @MarkB。 - 与此答案相同,您可以直接使用 SELECT 语句从 CTE 中删除。即使用;WITH CTE AS (SELECT ....) DELETE FROM CTE,但我建议您深入了解原始问题。
【解决方案3】:

一种可能的解释是有两个表,每个表都在不同的模式中。也许如果您对两个架构都拥有select 权限,但只有一个架构拥有delete 权限,SQL Server 可能会为delete 选择不同的表。

要验证这一点,请在表前加上架构名称(默认架构是 dbo

FROM schema1.fm104d

(未测试,只是一个想法,无法访问SQL Server安装atm。)

【讨论】:

  • 好建议,但遗憾的是,在这种情况下,只有一个 - dbo.fm104d
【解决方案4】:

对于您的选择,将ISDATE(pull_date) 添加到选择列表中以确定这些影响案例语句的哪一部分。还要查看 pull_date,看看这些拒绝删除的违规者中常见的字符串格式是否存在模式。

这可能与 Convert 和 IsDate 的确定性有关:

“ISDATE 仅在与 CONVERT 函数一起使用时具有确定性,如果指定了 CONVERT 样式参数,并且样式不等于 0、100、9 或 109。”

请参阅此处的几个示例,其中 convert 嵌套在 isdate 中:

http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-programming/181/CAST-CONVERT-nondeterministic

所以尝试调整你的 where 子句,看看是否有帮助。另请注意“ISDATE 的返回值可能受 LANGUAGE 和 DATEFORMAT 设置的影响。”因此,在这些方面,您的服务器上的某些内容可能发生了变化。为什么它会影响删除但不影响选择仍然很奇怪。

【讨论】:

    【解决方案5】:

    试试这个怎么样,看看你是否可以先评估你的 pull_date 列然后删除记录。

    DELETE FROM fm104d
    WHERE Location = 18 
       AND Pull_date IN
       (
          SELECT CONVERT (DATETIME,
             CASE 
                WHEN ISDATE(pull_Date) = 0
                   THEN '19000101'
                ELSE pull_date
             END) AS pull_date
          FROM fm104d 
          WHERE pull_date > DATEADD(DAY, -7, GETDATE())
       )
    

    【讨论】:

    • 如果pull_date 不是正确的datetime 值,您认为会发生什么?虽然您的子查询正在显式和安全地转换此列,但外部查询正在隐式执行它并且......繁荣!
    【解决方案6】:

    在我看来,当pull_date 不是日期时,您永远不想删除。
    尝试消除显式字符串替换......也许SELECTDELETE之间的解析不同

    DELETE 
    FROM 
        fm104d 
    WHERE 
        [location] = '18' --NOTE if this is an int, then just try with 18, no dits
        AND (
             CASE ISDATE([pull_date])
             WHEN 1 THEN
                 CAST([pull_date] AS DATETIME)
             ELSE
                 NULL
             END  >  DATEADD(DAY, -7, GETDATE())
            ) 
    

    编辑:请注意,这与您的 SQL完全不匹配,因为在您的 SQL 中,如果您穿越到 1900 年 1 月 1 日,它 无论如何删除你的行......我猜这实际上不是你的意图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-14
      • 1970-01-01
      • 1970-01-01
      • 2012-04-11
      • 1970-01-01
      • 1970-01-01
      • 2013-07-07
      相关资源
      最近更新 更多