【问题标题】:Is the computation of generated column triggered always when update a row?更新行时是否总是触发生成列的计算?
【发布时间】:2017-03-15 19:23:24
【问题描述】:

我在 MySQL 5.7 中有一个包含几十列的表。其中之一是生成的列(存储的,而不是虚拟的),它使用大表达式来计算基于列 A、B 和 C 的值,所以我猜 MySQL 在插入新行时需要一些额外的时间来计算值或更新。

我的简单问题是:

当我更新一行中的其他列(F、G 等)时,是否也会触发计算?

你能给我一些参考(链接)来证明你的答案吗?

谢谢

编辑:

我已经阅读了@Barmar 建议的 MySQL official documentation

STORED:在插入行时评估和存储列值 或更新。

如您所见,它说 inserted 或 updated 但我猜 updated 实际上意味着:如果相关列已更新 因为我认为 MySQL 足够聪明,如果这些列没有更新,则不会执行计算。这其实是我想确认的假设。

【问题讨论】:

    标签: mysql calculated-columns


    【解决方案1】:

    对于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_fieldsupdate_generated_write_fields 是评估生成字段表达式的相关函数。您还可以看到 gencolconst 的常量表达式未在更新中求值。

    同样不幸的是(仅作为旁注),该表上纯粹存在触发器将导致对update_generated_write_fields 的第二次调用以及对生成的列的第二次评估(如果它们已被第一次更新) -没关系,例如一个insert 触发器而你正在做一个update,任何触发器的纯粹存在就足够了。

    【讨论】:

    • 对我来说足够清楚,所以我接受了正确的答案。谢谢!
    【解决方案2】:

    来自MySQL documentation

    • STORED:在插入或更新行时评估和存储列值。

    这清楚地表明当您更新该行的其他列时会触发计算。

    【讨论】:

    • 谢谢@Barmar。我已经阅读了 MySQL 文档(我应该把它放在问题中,抱歉),但我很难相信如果没有相关列被更新,就像它返回 0 一样,MySQL 不够聪明,无法阻止计算当您使用已具有的相同值更新行时,受影响的行
    • 啊,我错过了你问题的那一部分。我的猜测是它足够聪明,可以检测到影响计算的列都没有被更改,但我不知道如何测试它。
    猜你喜欢
    • 2020-09-02
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    • 2017-01-15
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多