查询优化器的任务是找到执行 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,告诉优化器自动确定值。