文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  ...  /  预处理语句和存储程序的缓存

10.10.3 预处理语句和存储程序的缓存

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

  • 预处理语句,包括在 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 *,将发生重新解析,但对于不访问表或视图的 SELECT *,则不会发生重新解析。

  • 当语句受到影响时,服务器会尽可能仅部分地重新解析它。请考虑以下 CASE 语句:

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

    如果元数据更改仅影响 WHEN when_expr3,则会重新解析该表达式。case_expr 和其他 WHEN 表达式不会重新解析。

重新解析使用在原始转换为内部形式时生效的默认数据库和 SQL 模式。

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

重新解析是自动执行的,但在发生的范围内,会降低预处理语句和存储程序的性能。

对于预处理语句,Com_stmt_reprepare 状态变量跟踪重新解析的次数。