8.9.5 优化器成本模型

为了生成执行计划,优化器使用成本模型,该模型基于对查询执行期间发生的各种操作的成本进行估算。优化器具有一组内置的默认“成本常数”,可用于制定有关执行计划的决策。

优化器还有一个成本估算数据库,可在执行计划构建期间使用。这些估计值存储在mysql系统数据库的server_costengine_costtable 中,并且可以随时进行配置。这些 table 的目的是使得可以轻松调整优化器在尝试得出查询执行计划时使用的成本估算。

费用模型的一般运作

可配置的优化器成本模型的工作方式如下:

  • 服务器在启动时将成本模型 table 读取到内存中,并在运行时使用内存中的值。table 中指定的任何非NULL成本估算值都优先于相应的已编译默认成本常量。任何NULL估计值都指示优化器使用编译后的默认值。

  • 在运行时,服务器可以重新读取成本 table。当动态加载存储引擎或执行FLUSH OPTIMIZER_COSTS语句时,会发生这种情况。

  • 成本 table 使服务器 Management 员可以通过更改 table 中的条目轻松调整成本估算。通过将条目的费用设置为NULL,也很容易恢复为默认值。优化器使用内存中的成本值,因此对 table 所做的更改应后跟FLUSH OPTIMIZER_COSTS才能生效。

  • Client 会话开始时当前的内存中成本估算将在整个会话中应用,直到结束。特别是,如果服务器重新读取成本 table,则任何更改的估算值仅适用于随后启动的会话。现有会话不受影响。

  • 成本 table 特定于给定的服务器实例。服务器不会将成本 table 更改复制到副本。

成本模型数据库

优化程序成本模型数据库由mysql系统数据库中的两个 table 组成,其中包含查询执行期间发生的操作的成本估算信息:

  • server_cost:用于一般服务器操作的优化程序费用估算

  • engine_cost:针对特定存储引擎的特定操作的优化程序费用估算

server_costtable 包含以下列:

  • cost_name

成本模型中使用的成本估算的名称。名称不区分大小写。如果服务器在读取此 table 时无法识别成本名称,则会向错误日志中写入警告。

  • cost_value

成本估算值。如果该值不是NULL,则服务器将其用作成本。否则,它将使用默认估计值(编译值)。 DBA 可以通过更新此列来更改成本估算。如果服务器在读取此 table 时发现成本值无效(非正值),则会向错误日志中写入警告。

要覆盖默认成本估算值(对于指定NULL的条目),请将成本设置为非NULL值。要恢复为默认值,请将值设置为NULL。然后执行FLUSH OPTIMIZER_COSTS告诉服务器重新读取成本 table。

  • last_update

最后一行的更新时间。

  • comment

与成本估算相关的描述性 Comments。 DBA 可以使用此列来提供有关成本估算行为何存储特定值的信息。

server_costtable 的主键是cost_name列,因此无法为任何成本估算创建多个条目。

服务器识别出server_costtable 的以下cost_name值:

  • disk_temptable_create_cost(默认 40.0),disk_temptable_row_cost(默认 1.0)

存储在基于磁盘的存储引擎(InnoDBMyISAM)中的内部创建的临时 table 的成本估算。增加这些值会增加使用内部临时 table 的成本估算,并使优化器更喜欢较少使用它们的查询计划。有关此类 table 的信息,请参见第 8.4.4 节“ MySQL 中的内部临时 table 使用”

与相应的内存参数(memory_temptable_create_costmemory_temptable_row_cost)的默认值相比,这些磁盘参数的默认值较大反映了处理基于磁盘的 table 的成本较高。

  • key_compare_cost(默认为 0.1)

比较记录键的成本。增加此值将导致查询计划比较多个键变得更加昂贵。例如,与避免使用索引进行排序的查询计划相比,执行filesort的查询计划变得相对昂贵。

  • memory_temptable_create_cost(默认为 2.0),memory_temptable_row_cost(默认为 0.2)

内部存储在MEMORY存储引擎中的临时 table 的成本估算。增加这些值会增加使用内部临时 table 的成本估算,并使优化器更喜欢较少使用它们的查询计划。有关此类 table 的信息,请参见第 8.4.4 节“ MySQL 中的内部临时 table 使用”

与相应磁盘参数(disk_temptable_create_costdisk_temptable_row_cost)的默认值相比,这些内存参数的默认值较小,反映了处理基于内存的 table 的成本较低。

  • row_evaluate_cost(默认为 0.2)

评估记录条件的成本。与检查行数较少的查询计划相比,增加该值会导致检查许多行的查询计划变得更加昂贵。例如,与读取较少行的范围扫描相比,table 扫描变得相对昂贵。

engine_costtable 包含以下列:

  • engine_name

此成本估算适用的存储引擎的名称。名称不区分大小写。如果值为default,则适用于所有没有自己命名条目的存储引擎。如果服务器在读取该 table 时无法识别引擎名称,则会向错误日志中写入警告。

  • device_type

此费用估算适用的设备类型。该列旨在为不同的存储设备类型(例如,硬盘驱动器与固态驱动器)指定不同的成本估算。当前,此信息未使用,并且 0 是唯一允许的值。

  • cost_name

server_costtable 中的相同。

  • cost_value

server_costtable 中的相同。

  • last_update

server_costtable 中的相同。

  • comment

server_costtable 中的相同。

engine_costtable 的主键是一个包含(cost_nameengine_namedevice_type)列的 Tuples,因此无法为这些列中的任何值组合创建多个条目。

服务器识别出engine_costtable 的以下cost_name值:

  • io_block_read_cost(默认为 1.0)

从磁盘读取索引或数据块的成本。与读取较少磁盘块的查询计划相比,增加该值会使读取许多磁盘块的查询计划变得更加昂贵。例如,与读取较少块的范围扫描相比,table 扫描变得相对昂贵。

  • memory_block_read_cost(默认为 1.0)

io_block_read_cost相似,但是代 table 从内存数据库缓冲区读取索引或数据块的开销。

如果io_block_read_costmemory_block_read_cost值不同,则执行计划可能会在同一查询的两次运行之间改变。假设内存访问的成本小于磁盘访问的成本。在这种情况下,在服务器启动之前,将数据读入缓冲池之前,您可能会获得与运行查询之后不同的计划,因为这样数据就会存储在内存中。

更改成本模型数据库

对于希望从其默认值更改成本模型参数的 DBA,请尝试将该值加倍或减半并测量效果。

更改io_block_read_costmemory_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;