8.9.1 控制查询计划评估

查询优化器的任务是找到执行 SQL 查询的最佳计划。因为“好的”计划和“不好的”计划之间的性能差异可能是几个数量级(即,数秒相对于数小时甚至数天),所以大多数查询优化器(包括 MySQL 的优化器)或多或少都进行了详尽的搜索以获得最佳选择所有可能的查询评估计划中的计划。对于联接查询,MySQL 优化器调查的可能计划的数量与查询中引用的 table 的数量成指数增长。对于少量 table(通常少于 7 到 10),这不是问题。但是,提交较大的查询时,花在查询优化上的时间可能很容易成为服务器性能的主要瓶颈。

一种更灵活的查询优化方法,使用户可以控制优化程序在搜索最佳查询评估计划时的详尽程度。通常的想法是,优化器调查的计划越少,则编译查询所花费的时间就越少。另一方面,由于优化器会跳过某些计划,因此可能会找不到最佳计划。

可以使用两个系统变量来控制优化器相对于评估的计划数量的行为:

  • optimizer_prune_level变量告诉优化器根据对每个 table 访问的行数的估计来跳过某些计划。我们的经验 table 明,这种“有根据的猜测”很少会错过最佳计划,并且可能会大大减少查询的编译时间。这就是为什么此选项默认为(optimizer_prune_level=1)的原因。但是,如果您认为优化器错过了更好的查询计划,则可以关闭此选项(optimizer_prune_level=0),这可能会导致查询编译花费更长的时间。请注意,即使使用此启发式方法,优化器仍会探索大约指数级的计划。

  • optimizer_search_depth变量指示优化器应该对每个不完整计划的“Future”进行多大的评估,以评估是否应进一步扩展该计划。较小的optimizer_search_depth值可能会导致查询编译时间缩短几个数量级。例如,如果optimizer_search_depth接近查询中的 table 数,那么具有 12、13,或更多 table 的查询可能很容易需要数小时甚至数天的时间来进行编译。同时,如果用optimizer_search_depth等于 3 或 4 进行编译,则对于同一查询,优化器可能会在不到一分钟的时间内完成编译。如果不确定optimizer_search_depth的合理值是多少,可以将此变量设置为 0,以告知优化器自动确定该值。