【问题标题】:Confirm before delete/update in SQL Management Studio?在 SQL Management Studio 中删除/更新之前确认?
【发布时间】:2010-09-21 20:00:37
【问题描述】:

因此,有人连续第二天清除了整个表的数据,而不是他们试图删除的一行,因为他们没有限定的 where 子句。

我一直在调整 mgmt studio 选项,但找不到确认选项。我知道其他数据库的其他工具也有。

【问题讨论】:

    标签: sql-server ssms


    【解决方案1】:

    首先,这就是审计表的用途。如果您知道谁删除了所有记录,您可以限制他们的数据库权限或从性能角度处理它们。在我办公室做这件事的最后一个人目前正在试用期。如果她再次这样做,她将被放开。如果您有权访问生产数据并确保您不会造成伤害,那么您就有责任是其中之一。这是一个性能问题,也是一个技术问题。您永远不会找到防止人们犯愚蠢错误的方法(数据库无法知道您是要删除表 a 还是删除 id = 100 的表 a 并且大多数人会自动点击确认)。您只能通过确保运行此代码的人负责并制定政策来帮助他们记住要做什么来尝试减少它们。对您的业务数据有不负责任行为模式的员工(尤其是在他们被警告之后)应该被解雇。

    其他人建议我们采取哪些措施来防止这种情况发生。我总是在我从查询窗口运行的删除中嵌入一个选择,以确保它只会删除我想要的记录。我们所有更改、插入或删除数据的生产代码都必须包含在事务中。如果它是手动运行的,则在看到受影响的记录数之前不要运行回滚或提交。

    使用嵌入式选择删除示例

    delete a
    --select a.* from 
    from table1 a 
    join table 2 b on a.id = b.id
    where b.somefield = 'test'
    

    但即使是这些技术也无法防止所有人为错误。不了解数据的开发人员可能会运行 select 并且仍然不了解它正在删除太多记录。当人们忘记提交或回滚并锁定系统时,在事务中运行可能意味着您会遇到其他问题。或者人们可能将它放在一个事务中并且仍然不假思索地点击提交,就像如果有一个消息框他们会点击确认一样。最好的预防措施是有一种方法可以快速从此类错误中恢复。从审计日志表中恢复往往比从备份中恢复更快。此外,您还可以知道谁犯了错误以及哪些记录受到了影响(也许您没有删除整个表,但您的 where 子句是错误的,并且您删除了一些错误的记录。)

    在大多数情况下,不应随时更改生产数据。您应该编写更改脚本并首先在 dev 上检查它。然后在 prod 上,您所要做的就是在不做任何更改的情况下运行脚本,而不是一次突出显示并运行小块。现在在现实世界中,这并不总是可行的,因为有时您只在需要修复的产品上修复损坏的东西(例如,当您的客户都无法登录时,因为关键数据已被删除)。在这种情况下,您可能无法先在 dev 上重现问题,然后再编写修复程序。当您遇到这些类型的问题时,您可能需要直接在 prod 上进行修复,并且您应该只有 dbas 或数据库分析师、配置经理或其他通常负责 prod 上数据的人而不是开发人员来修复。一般而言,开发人员不应有权访问 prod。

    【讨论】:

      【解决方案2】:

      锁定它:

      REVOKE删除所有表的权限。

      放入审计触发器和审计表。

      创建参数化删除 SP 并仅授予根据需要执行的权限。

      【讨论】:

        【解决方案3】:

        有没有一种方法可以在不提供对 SQL 的原始访问权限的情况下为用户提供他们需要的结果?如果您至少有一个单独的“WHERE”输入框,则可以将其默认为“WHERE 1 = 0”或其他内容。

        我认为也必须有一种方法可以将这些从事务日志中删除。但可能不会不回滚所有内容,然后有选择地重新应用致命错误之后出现的任何内容。

        另一个丑陋的选择是创建一个触发器,将所有 DELETE(可能超过某个最小记录数)写入日志表。

        【讨论】:

        • 你丑陋的选择是所有负责任的企业都会做的。它们被称为审计表,它们属于每个具有业务关键信息的数据库。
        【解决方案4】:

        因此,有人连续第二天清除了整个表的数据,而不是他们试图删除的一行,因为他们没有合格的 where 子句

        可能唯一的解决方案是将 someone 替换为 someone else ;)。否则他们总会找到解决方法

        最终限制该人的数据库访问,并为他们提供存储过程,该存储过程采用 where 子句中使用的参数,并授予他们执行该存储过程的访问权限。

        【讨论】:

          【解决方案5】:

          我建议您应该始终首先编写带有 WHERE 子句的 SELECT 语句并执行它以实际查看您的 DELETE 命令将删除哪些行。然后只需使用相同的 WHERE 子句执行 DELETE。这同样适用于 UPDATE。

          【讨论】:

          • 我同意,这绝对是最佳做法,如果每个人都遵循这种做法,我现在就不会打字了 :)
          【解决方案6】:

          在 SSMS 2005 中,您可以在工具|选项|查询执行|SQL Server|ANSI 下启用此选项...检查SET IMPLICIT_TRANSACTIONS。这将需要提交来影响未来连接的更新/删除查询。

          对于当前查询,转到查询|查询选项|执行|ANSI 并选中相同的框。

          This page 也有关于 SSMS 2000 的说明,如果您正在使用的话。

          正如其他人指出的那样,这并不能解决根本原因:在您创建的每个新查询的末尾粘贴 COMMIT 几乎与首先触发查询一样容易。

          【讨论】:

            【解决方案7】:

            穿上你最好的 Trogdor 和 Burninate,直到他们学会使用 WHERE 子句。

            最好的建议是让那些在数据库中乱七八糟的垃圾在测试时使用事务。它对防止“哎呀”时刻大有帮助。需要注意的是,现在您必须告诉他们 COMMIT 或 ROLLBACK,因为他们肯定会至少锁定您的数据库一次。

            【讨论】:

              【解决方案8】:

              这就是为什么我认为你应该永远:

              1 在部署到生产环境之前使用在开发数据库上测试过的存储过程

              2 选择删除前的数据

              3 使用面试和绩效评估流程筛选开发人员 :)

              4 根据他们删除/不删除多少数据库表来评估性能

              5 将生产数据视为有毒并非常害怕

              【讨论】:

              • 我认为 3 和 4 有点傲慢,但 2 和 5 是合理的建议。
              【解决方案9】:

              在 Tools>Options>Query Execution>SQL Server>ANSI 下,您可以启用 Implicit Transactions 选项,这意味着您不需要显式包含 Begin Transaction 命令。

              这样做的明显缺点是您可能忘记在末尾添加 Commit(或 Rollback),或者更糟糕的是,您的同事默认情况下会在每个脚本的末尾添加 Commit。

              你可以把马牵到水边……

              您可能会建议他们在执行任何操作(取决于您的数据库的大小)之前始终进行临时备份,以防万一。

              【讨论】:

              • 我同意所有这些建议,其中最好的部分是“牵马入水”。如果没有具体的东西来阻止用户,所有这些都会在某个时候失败。感谢您的建议。
              • 这通常会导致用户不假思索地反射性地确认。
              【解决方案10】:

              在运行DELETE 语句之前尝试使用BEGIN TRANSACTION

              那你可以选择COMMIT或者ROLLBACK一样。

              【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-03-11
              • 2012-05-30
              • 1970-01-01
              • 2015-12-27
              • 2016-07-26
              相关资源
              最近更新 更多