对于update-statement,只有在指定要修改引用的列时,MySQL才会重新评估生成的存储列(注意:不一定更改,只是在要修改的列列表中) .您可以验证这一点,例如带有调试版本。
create table test (
id int auto_increment primary key,
x int,
y int,
gencolx int as (2*x) stored,
gencolconst int as (2) stored
);
insert into test (x, y) values (2, 2);
update test set x = 4;
update test set y = 5;
update test set x = 4;
第一个update 将触发对依赖于x 的生成列gencolx 的评估:
THD::decide_logging_format: info: query: update test set x = 4
update_generated_read_fields: info: field 'gencolx' - skipped
update_generated_read_fields: info: field 'gencolconst' - skipped
update_generated_write_fields: info: field 'gencolx' - updated
update_generated_write_fields: info: field 'gencolconst' - skipped
第二个update 不会更新在任何生成的列中使用的列,因此不会重新计算它们:
THD::decide_logging_format: info: query: update test set y = 5
update_generated_read_fields: info: field 'gencolx' - skipped
update_generated_read_fields: info: field 'gencolconst' - skipped
update_generated_write_fields: info: field 'gencolx' - skipped
update_generated_write_fields: info: field 'gencolconst' - skipped
不幸的是,MySQL 不会检查该值是否实际已更改,只要该列是目标列。所以最后一个update,实际上保持x 的值不变,仍然会导致对依赖生成列的评估,因为列x 是要在update 语句中修改的列:
THD::decide_logging_format: info: query: update test set x = 4
update_generated_read_fields: info: field 'gencolx' - skipped
update_generated_read_fields: info: field 'gencolconst' - skipped
update_generated_write_fields: info: field 'gencolx' - updated
update_generated_write_fields: info: field 'gencolconst' - skipped
mysql_update: info: 0 records updated
顺便说一句,如果您使用例如update test set x = x,不会改变任何行。
update_generated_read_fields 和 update_generated_write_fields 是评估生成字段表达式的相关函数。您还可以看到 gencolconst 的常量表达式未在更新中求值。
同样不幸的是(仅作为旁注),该表上纯粹存在触发器将导致对update_generated_write_fields 的第二次调用以及对生成的列的第二次评估(如果它们已被第一次更新) -没关系,例如一个insert 触发器而你正在做一个update,任何触发器的纯粹存在就足够了。