为了生成执行计划,优化器使用一个成本模型,该模型基于对查询执行过程中发生的各种操作成本的估计。优化器具有一组编译好的默认“成本常数”,可供其在关于执行计划的决策中使用。
优化器还拥有一个成本估计数据库,用于在执行计划构建过程中使用。这些估计存储在 mysql
系统数据库中的 server_cost
和 engine_cost
表中,并且可以在任何时候配置。这些表的目的是使 DBA 可以轻松地调整优化器在尝试得出查询执行计划时使用的成本估计。
可配置的优化器成本模型的工作原理如下
服务器在启动时将成本模型表读入内存,并在运行时使用内存中的值。表中指定的任何非
NULL
成本估计优先于相应的编译好的默认成本常数。任何NULL
估计表示优化器使用编译好的默认值。在运行时,服务器可能会重新读取成本表。这发生在动态加载存储引擎时,或在执行
FLUSH OPTIMIZER_COSTS
语句时。成本表使服务器管理员可以通过更改表中的条目轻松地调整成本估计。也可以通过将条目的成本设置为
NULL
来轻松地恢复到默认值。优化器使用内存中的成本值,因此对表的更改应随后执行FLUSH OPTIMIZER_COSTS
以使更改生效。在客户端会话开始时当前的内存中成本估计在该会话结束之前一直适用。特别是,如果服务器重新读取成本表,任何更改的估计值仅适用于随后启动的会话。现有会话不受影响。
成本表特定于给定的服务器实例。服务器不会将成本表更改复制到副本。
优化器成本模型数据库包含 mysql
系统数据库中的两个表,这些表包含查询执行期间发生的各种操作的成本估计信息。
server_cost
表包含以下列
cost_name
成本模型中使用的成本估计的名称。名称不区分大小写。如果服务器在读取此表时无法识别成本名称,它会在错误日志中写入警告。
cost_value
成本估计值。如果该值为非
NULL
,则服务器使用它作为成本。否则,它使用默认估计(编译好的值)。DBA 可以通过更新此列来更改成本估计。如果服务器在读取此表时发现成本值为无效值(非正数),它将在错误日志中写入警告。要覆盖默认成本估计(对于指定
NULL
的条目),请将成本设置为非NULL
值。要恢复到默认值,请将值设置为NULL
。然后执行FLUSH OPTIMIZER_COSTS
以告知服务器重新读取成本表。last_update
最后一次更新行的时刻。
comment
与成本估计相关的描述性注释。DBA 可以使用此列来提供有关成本估计行存储特定值的原因的信息。
default_value
成本估计的默认(编译好的)值。此列是一个只读生成的列,即使相关的成本估计发生了更改,它也会保留其值。对于在运行时添加到表的行,此列的值为
NULL
。
表 server_cost
的主键是 cost_name
列,因此无法为任何成本估算创建多个条目。
服务器识别表 server_cost
中的以下 cost_name
值。
disk_temptable_create_cost
、disk_temptable_row_cost
存储在基于磁盘的存储引擎(
InnoDB
或MyISAM
)中的内部创建的临时表的成本估算。增加这些值会增加使用内部临时表的成本估算,并使优化器更倾向于使用内部临时表较少的查询计划。有关此类表的详细信息,请参见 第 10.4.4 节,“MySQL 中的内部临时表使用”。与相应的内存参数(
memory_temptable_create_cost
、memory_temptable_row_cost
)的默认值相比,这些磁盘参数的默认值更大,反映了处理基于磁盘的表的成本更高。key_compare_cost
比较记录键的成本。增加此值会导致比较多个键的查询计划变得更加昂贵。例如,执行
filesort
的查询计划将变得相对更昂贵,相比于通过使用索引来避免排序的查询计划。memory_temptable_create_cost
、memory_temptable_row_cost
存储在
MEMORY
存储引擎中的内部创建的临时表的成本估算。增加这些值会增加使用内部临时表的成本估算,并使优化器更倾向于使用内部临时表较少的查询计划。有关此类表的详细信息,请参见 第 10.4.4 节,“MySQL 中的内部临时表使用”。与相应的磁盘参数(
disk_temptable_create_cost
、disk_temptable_row_cost
)的默认值相比,这些内存参数的默认值更小,反映了处理基于内存的表的成本更低。row_evaluate_cost
评估记录条件的成本。增加此值会导致检查许多行的查询计划变得更加昂贵,相比于检查较少行的查询计划。例如,表扫描将变得相对更昂贵,相比于读取较少行的范围扫描。
表 engine_cost
包含以下列
engine_name
此成本估算适用的存储引擎的名称。名称不区分大小写。如果该值为
default
,则它适用于所有没有自身命名条目的存储引擎。如果服务器在读取此表时不识别引擎名称,它将向错误日志写入警告。device_type
此成本估算适用的设备类型。该列旨在为不同的存储设备类型指定不同的成本估算,例如硬盘驱动器与固态驱动器。目前,此信息未被使用,0 是唯一允许的值。
cost_name
与表
server_cost
中相同。cost_value
与表
server_cost
中相同。last_update
与表
server_cost
中相同。comment
与表
server_cost
中相同。default_value
成本估算的默认(编译时)值。此列是一个只读生成列,即使关联的成本估算发生更改,它也会保留其值。对于在运行时添加到表的行,此列的值为
NULL
,但如果该行具有与原始行之一相同的cost_name
值,则default_value
列的值与该行相同。
表 engine_cost
的主键是包含 (cost_name
、engine_name
、device_type
) 列的元组,因此无法为这些列中任何值的组合创建多个条目。
服务器识别表 engine_cost
中的以下 cost_name
值。
io_block_read_cost
从磁盘读取索引或数据块的成本。增加此值会导致读取许多磁盘块的查询计划变得更加昂贵,相比于读取较少磁盘块的查询计划。例如,表扫描将变得相对更昂贵,相比于读取较少块的范围扫描。
memory_block_read_cost
类似于
io_block_read_cost
,但表示从内存中数据库缓冲区读取索引或数据块的成本。
如果 io_block_read_cost
和 memory_block_read_cost
值不同,则相同查询的两次运行之间的执行计划可能会发生变化。假设内存访问的成本低于磁盘访问的成本。在这种情况下,在服务器启动之前,数据还没有被读入缓冲池,您可能会得到与查询运行后不同的计划,因为那时数据已在内存中。
对于希望更改成本模型参数默认值的 DBA,请尝试将值翻倍或减半,并测量其影响。
对 io_block_read_cost
和 memory_block_read_cost
参数的更改最有可能产生有价值的结果。这些参数值使数据访问方法的成本模型能够考虑从不同来源读取信息的成本;也就是说,从磁盘读取信息的成本与从内存缓冲区读取信息的成本。例如,在其他所有条件相同的情况下,将 io_block_read_cost
设置为大于 memory_block_read_cost
的值会导致优化器更倾向于读取已在内存中保存的信息的查询计划,而不是必须从磁盘读取信息的查询计划。
此示例显示如何更改 io_block_read_cost
的默认值
UPDATE mysql.engine_cost
SET cost_value = 2.0
WHERE cost_name = 'io_block_read_cost';
FLUSH OPTIMIZER_COSTS;
此示例显示如何仅更改 InnoDB
存储引擎的 io_block_read_cost
值
INSERT INTO mysql.engine_cost
VALUES ('InnoDB', 0, 'io_block_read_cost', 3.0,
CURRENT_TIMESTAMP, 'Using a slower disk for InnoDB');
FLUSH OPTIMIZER_COSTS;