MySQL 8.0 参考手册  / 第8章优化  / 8.10 缓冲和缓存  /  8.10.4 准备语句和存储程序的缓存

8.10.4 准备语句和存储程序的缓存

对于客户端可能在会话期间多次执行的某些语句,服务器会将语句转换为内部结构并缓存该结构以在执行期间使用。缓存使服务器能够更有效地执行,因为它避免了在会话期间再次需要时重新转换语句的开销。这些语句发生转换和缓存:

  • 准备好的语句,包括在 SQL 级别处理的语句(使用PREPARE语句)和使用二进制客户端/服务器协议处理的语句(使用 mysql_stmt_prepare()C API 函数)。系统变量控制服务器缓存的 max_prepared_stmt_count 语句总数。(所有会话中准备好的语句数的总和。)

  • 存储程序(存储过程和函数、触发器和事件)。在这种情况下,服务器转换并缓存整个程序主体。stored_program_cache系统变量指示服务器在每个会话中缓存的存储程序的近似数量 。

服务器在每个会话的基础上为准备好的语句和存储的程序维护缓存。其他会话无法访问为一个会话缓存的语句。当会话结束时,服务器会丢弃为其缓存的所有语句。

当服务器使用缓存的内部语句结构时,必须注意该结构不会过时。语句使用的对象可能发生元数据更改,导致当前对象定义与内部语句结构中表示的定义不匹配。DDL 语句会发生元数据更改,例如创建、删除、更改、重命名或截断表的语句,或者分析、优化或修复表的语句。表内容更改(例如,使用INSERTUPDATE)不会更改元数据,也不会更改SELECT语句。

这是问题的说明。假设客户准备了这条语句:

PREPARE s1 FROM 'SELECT * FROM t1';

SELECT *内部结构中扩展到表中的列列表。如果用 修改了表中的列集ALTER TABLE,则准备好的语句将过时。如果服务器在下次客户端执行时没有检测到这种变化s1,准备好的语句将返回不正确的结果。

为避免由准备好的语句引用的表或视图的元数据更改引起的问题,服务器会检测这些更改并在下次执行时自动重新准备该语句。也就是说,服务器重新解析语句并重建内部结构。重新解析也会在引用的表或视图从表定义缓存中刷新后发生,或者隐式地为缓存中的新条目腾出空间,或者显式地由于FLUSH TABLES.

同样,如果存储程序使用的对象发生更改,服务器会重新分析程序中受影响的语句。

服务器还检测表达式中对象的元数据更改。这些可能用于特定于存储程序的语句,例如DECLARE CURSOR或流控制语句,例如 IFCASERETURN

为避免重新分析整个存储的程序,服务器仅在需要时重新分析程序中受影响的语句或表达式。例子:

  • 假设表或视图的元数据已更改。SELECT *对访问表或视图的程序内的 a进行重新分析,但不对SELECT *不访问表或视图的 a 进行重新分析。

  • 当一条语句受到影响时,如果可能,服务器只会对其进行部分重新解析。考虑这个 CASE声明:

    CASE case_expr
      WHEN when_expr1 ...
      WHEN when_expr2 ...
      WHEN when_expr3 ...
      ...
    END CASE

    如果元数据更改仅影响,则重新解析该表达式。 并且其他表达式不会被重新解析。 WHEN when_expr3case_exprWHEN

重新分析使用对原始转换为内部形式有效的默认数据库和 SQL 模式。

服务器最多尝试重新解析 3 次。如果所有尝试都失败,则会发生错误。

重新解析是自动进行的,但就其发生而言,会降低准备语句和存储程序的性能。

对于准备好的语句, Com_stmt_reprepare 状态变量跟踪重新准备的次数。