查询优化器的任务是找到执行 SQL 查询的最佳计划。由于“好” 和 “坏” 计划之间的性能差异可能相差几个数量级(即秒与小时或甚至几天),大多数查询优化器,包括 MySQL 的优化器,都会对所有可能的查询评估计划执行或多或少的穷举搜索以找到最佳计划。对于连接查询,MySQL 优化器调查的可能计划数量随着查询中引用的表数量呈指数增长。对于少量表(通常少于 7 到 10 个),这不成问题。但是,当提交较大的查询时,用于查询优化的花费时间很容易成为服务器性能的主要瓶颈。
一种更灵活的查询优化方法使用户能够控制优化器在搜索最佳查询评估计划时的穷举程度。总体思路是,优化器调查的计划越少,它在编译查询上花费的时间就越少。另一方面,由于优化器跳过了某些计划,它可能会错过找到最佳计划的机会。
可以使用两个系统变量控制优化器在评估计划数量方面的行为
optimizer_prune_level
变量指示优化器根据对每个表访问的行数的估计跳过某些计划。我们的经验表明,这种“有根据的猜测” 很少会错过最佳计划,并且可以显着缩短查询编译时间。这就是为什么默认情况下此选项处于开启状态(optimizer_prune_level=1
)。但是,如果您认为优化器错过了更好的查询计划,则可以关闭此选项(optimizer_prune_level=0
),但存在查询编译可能花费更长时间的风险。请注意,即使使用这种启发式方法,优化器仍然会探索大约呈指数级的计划数量。optimizer_search_depth
变量指示优化器应该查看每个未完成计划的“未来” 多远以评估是否应该进一步扩展该计划。较小的optimizer_search_depth
值可能会导致查询编译时间减少几个数量级。例如,如果optimizer_search_depth
接近查询中的表数,则具有 12、13 或更多表的查询可能很容易需要数小时甚至数天才能编译。同时,如果使用optimizer_search_depth
等于 3 或 4 编译,则对于相同的查询,优化器可能在不到一分钟的时间内完成编译。如果您不确定optimizer_search_depth
的合理值是多少,则可以将此变量设置为 0 以指示优化器自动确定该值。