【问题标题】:How to test an SQL Update statement before running it?如何在运行 SQL Update 语句之前对其进行测试?
【发布时间】:2012-06-16 04:54:26
【问题描述】:

在某些情况下,在生产环境中运行 UPDATE 语句可以节省时间。然而,一个糟糕的更新可能比最初的问题更糟糕。

没有使用测试数据库,有哪些选项可以告诉更新语句在运行之前会做什么?

【问题讨论】:

    标签: mysql sql database testing myisam


    【解决方案1】:

    事务呢?它们具有 ROLLBACK 功能。

    @见https://dev.mysql.com/doc/refman/5.0/en/commit.html

    例如:

    START TRANSACTION;
    SELECT * FROM nicetable WHERE somthing=1;
    UPDATE nicetable SET nicefield='VALUE' WHERE somthing=1;
    SELECT * FROM nicetable WHERE somthing=1; #check
    
    COMMIT;
    # or if you want to reset changes 
    ROLLBACK;
    
    SELECT * FROM nicetable WHERE somthing=1; #should be the old value
    

    回答下面@ri​​ckozoe 的问题:

    通常这些行不会被执行一次。在 PHP 中你会写这样的东西(也许有点干净,但想快速回答;-)):

    $MysqlConnection->query('START TRANSACTION;');
    $erg = $MysqlConnection->query('UPDATE MyGuests SET lastname='Doe' WHERE id=2;');
    if($erg)
        $MysqlConnection->query('COMMIT;');
    else
        $MysqlConnection->query('ROLLBACK;');
    

    另一种方法是使用 MySQL 变量(参见 https://dev.mysql.com/doc/refman/5.7/en/user-variables.html 和 https://stackoverflow.com/a/18499823/1416909 ):

    # do some stuff that should be conditionally rollbacked later on
    
    SET @v1 := UPDATE MyGuests SET lastname='Doe' WHERE id=2;
    IF(v1 < 1) THEN
        ROLLBACK;
    ELSE
        COMMIT;
    END IF;
    

    但我建议使用您最喜欢的编程语言中可用的语言包装器。

    【讨论】:

    • 这会对嵌套事务产生意想不到的结果。
    • 你能举个例子吗?
    • @JCM 和其他人,你怎么知道它是否成功更新语句在第 3 行成功,以便你可以提交和回滚?
    【解决方案2】:

    除了使用 Imad 所说的事务(无论如何这应该是强制性的)之外,您还可以通过使用与 UPDATE 相同的 WHERE 子句运行选择来进行完整性检查。

    所以如果你 UPDATE 是

    UPDATE foo
      SET bar = 42
    WHERE col1 = 1
      AND col2 = 'foobar';
    

    以下将显示哪些行将被更新:

    SELECT *
    FROM foo
    WHERE col1 = 1
      AND col2 = 'foobar';
    

    【讨论】:

    • 那么最好使用事务来检查数据。假设他想检查结果,我得出结论他的语句比“SET bar = 42”更复杂,因此在他的会话中,他将能够进行多个查询来测试结果数据集......
    • @ImadMoqaddem:我同意,这就是为什么我写了“除了使用 Imad 所说的交易
    • 如果你有FOREIGN KEY UPDATE CASCADE你的sql失败
    • @Green:“失败”是什么意思?
    【解决方案3】:

    自动提交关闭 ...

    MySQL

    set autocommit=0;
    

    它为当前会话设置自动关闭。

    你执行你的语句,看看它发生了什么变化,如果它是错误的则回滚,或者如果它是你所期望的则提交!

    编辑:使用事务而不是运行选择查询的好处是您可以更轻松地检查结果集。

    【讨论】:

    • @dystroy:每个明智的 DBMS 都支持事务。
    • 请记住快速提交或回滚事务,否则您可能会阻塞其他事务 - 最坏的情况是会使您的应用程序停止运行。执行查询不是一个好主意,然后吃午饭,然后回来查看结果! :-)
    • @GaryMcGill:挂起的事务(至少在现代 DBMS 中)只会阻塞其他 write 事务。
    • @dystroy :不幸的是,MyISAM 无处不在,而我不是 DBA。
    • 添加了Sql语句:)
    【解决方案4】:

    我知道这是其他答案的重复,但它有一些情感支持来采取额外的步骤来测试更新:D

    对于测试更新,哈希 # 是你的朋友。

    如果您有如下更新语句:

    UPDATE 
    wp_history
    SET history_by="admin"
    WHERE
    history_ip LIKE '123%'
    

    您散列 UPDATE 和 SET 进行测试,然后将它们散列回来:

    SELECT * FROM
    #UPDATE
    wp_history
    #SET history_by="admin"
    WHERE
    history_ip LIKE '123%'
    

    它适用于简单的语句。

    另一个实际强制性的解决方案是,在生产表上使用更新时获取副本(备份副本)。 Phpmyadmin > 操作 > 复制:table_yearmonthday。

    【讨论】:

      【解决方案5】:

      不是一个直接的答案,但我已经看到了许多可以通过首先输入WHERE 子句来避免的糟糕的产品数据情况!有时WHERE 1 = 0 也可以帮助将工作声明安全地放在一起。并且查看估计的执行计划,这将估计受影响的行,可能很有用。除此之外,在您如其他人所说的那样回滚的事务中。

      【讨论】:

      • @SystemParadox - 没什么,尽管WHERE 1 = 0 更便于携带,如果有人遇到使用不同 DBMS 的人。例如,SQL Server 不接受WHERE FALSE
      【解决方案6】:

      制作一个SELECT

      如果你有的话

      UPDATE users SET id=0 WHERE name='jan'

      转换成

      SELECT * FROM users WHERE name='jan'

      【讨论】:

        【解决方案7】:

        在您要测试的这些情况下,最好只关注当前列值和即将更新列值。 p>

        请查看我为更新 WHMCS 价格而编写的以下代码:

        # UPDATE tblinvoiceitems AS ii
        
        SELECT                        ###  JUST
            ii.amount AS old_value,   ###  FOR
            h.amount AS new_value     ###  TESTING
        FROM tblinvoiceitems AS ii    ###  PURPOSES.
        
        JOIN tblhosting AS h ON ii.relid = h.id
        JOIN tblinvoices AS i ON ii.invoiceid = i.id
        
        WHERE ii.amount <> h.amount   ### Show only updatable rows
        
        # SET ii.amount = h.amount
        

        通过这种方式,我们可以清楚地比较现有值与新值。

        【讨论】:

          【解决方案8】:

          另一种选择是向 MySQL 询问查询计划。这告诉你两件事:

          • 查询中是否有语法错误,如果有,查询计划命令本身会失败
          • MySQL 计划如何执行查询,例如它将使用什么索引

          在 MySQL 和大多数 SQL 数据库中,查询计划命令是 describe,所以你可以这样做:

          describe update ...;
          

          【讨论】:

            【解决方案9】:

            使用您在更新查询中应用的所有where 条件在同一张表上运行选择查询。

            【讨论】:

              猜你喜欢
              • 2012-03-01
              • 2013-02-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-03-04
              • 2014-03-28
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多