如何在运行 SQLUpdate 语句之前对其进行测试?

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

除了使用测试数据库之外,在运行更新语句之前,还有哪些选项可以告诉您更新语句将执行哪些操作?

143976 次浏览

将自动提交设置为 OFF。

在 MySQL 中,set autocommit=0;设置当前会话的自动提交关闭。

您执行您的语句,查看它已经更改了什么,然后如果错误则回滚,如果正如您所期望的那样则提交!

The benefit of using transactions instead of running select query is that you can check the resulting set easily.

Run select query on same table with all where conditions you are applying in update query.

In addition to using a transaction as Imad has said (which should be mandatory anyway) you can also do a sanity check which rows are affected by running a select using the same WHERE clause as the UPDATE.

因此,如果您更新是

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

下面将显示将更新哪些行:

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

把它做成 SELECT,

比如说

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

转换成

SELECT * FROM users WHERE name='jan'

我已经看到了许多棘手的数据情况,本来可以避免 首先键入 WHERE子句!有时,WHERE 1 = 0也可以帮助安全地将工作语句组合在一起。查看将估计受影响的行的估计执行计划可能很有用。除此之外,在其他人所说的回滚事务中。

您也可以对 MySQL 使用 WHERE FALSE,但是请记住,其他 DBMS (如 SQLServer)不会接受这一点。

对于测试更新,hash # 是您的朋友。

如果你有一个更新语句,比如:

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%'

它适用于简单的语句。

另一个实际上是强制性的解决方案是,每当在生产表上使用 update 时,都要获得一个副本(备份副本)。Phpmyadmin > operation > copy: table _ year monthday.对于 < = 100M 的表,只需要几秒钟。

交易怎么样? 他们有回退功能。

@see 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

回答来自@rickozoe 的问题:

In general these lines will not be executed as once. In PHP f.e. you would write something like that (perhaps a little bit cleaner, but wanted to answer quick ;-) ):

$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;

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

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

请看下面的代码,我已经写了更新 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

This way we clearly compare already existing values versus new values.

另一个选择是向 MySQL 询问查询计划:

  • 查询中是否存在语法错误,如果存在,则查询计划命令本身将失败
  • MySQL 计划如何执行查询,例如它将使用哪些索引

在 MySQL 和大多数 SQL 数据库中,query plan 命令是 describe,因此可以这样做:

describe update ...;

只需运行 EXPLAIN查询。所以只要在你的查询之前写上 EXPLAIN这个词,它就会告诉你它将如何执行你的更新查找行,等等。但它无法执行。但是,如果有任何语法错误,它会让您知道。那就解释一下!

EXPLAIN UPDATE ... SET ...