【问题标题】:MySQL: random effect on ANALYZE TABLEMySQL:对分析表的随机影响
【发布时间】:2013-01-14 23:26:38
【问题描述】:

我有 3 个innodb 表,分别是 A、B 和 C。有一个查询可以连接这三个表以生成结果。

SELECT A.a, B.b, C.c
from A 
join B on A.id = B.a_id 
join C on C.id = B.c_id
where A.a = 'example' and B.b < 10;

一开始,当我使用“解释”命令测试查询时,它给了我以下命令:

B -- C -- A

但是,这不是最佳选择。所以我对所有表运行“分析表”,它给了我:

A -- B -- C

,我认为这是正确的顺序。

然后我将SQL部署到生产中,1​​个月后,无缘无故的执行计划切换回了错误的选项,即B--C--A。之后,我尝试再次运行ANALYZE TABLE几次,不过,这一次,结果让我感到困惑。有时它也给我 B--C--A,有时它给我 A--B--C,有时甚至是其他执行计划。

所以我的问题是:

  1. 为什么部署后执行计划会发生变化?
  2. 除了固定执行计划(数据更新和变化很快,所以最优计划可能在未来发生变化),有没有办法保证最优计划总是得到保证?

【问题讨论】:

    标签: mysql indexing sql-execution-plan explain


    【解决方案1】:

    优化器根据有关表大小、基数、值分布、索引等的内存统计信息来选择重新排序表和使用索引。这些统计信息是估计,并非绝对准确在任何时候。

    InnoDB 会不时更新其统计信息,这就是您在运行 ANALZYE TABLE 时可能导致发生的情况。

    但是,在某些情况下,内存中的统计信息正处于使优化器做出不同选择的风口浪尖上,因此您会看到这种翻转行为。

    您可以通过在查询中指定index hints 来覆盖优化器选择索引的默认算法。

    您可以通过指定STRAIGHT_JOIN 来覆盖优化器对表重新排序的默认算法。这意味着您希望它按照您在 FROM 子句中给出的顺序读取表,而不是重新排序。

    您可以使用 STRAIGHT_JOIN 作为查询修饰符(如 DISTINCT)。放在 SELECT 之后:

    SELECT STRAIGHT_JOIN A.a, B.b, C.c
    from A 
    join B on A.id = B.a_id 
    join C on C.id = B.c_id
    where A.a = 'example' and B.b < 10;
    

    但是要小心不要过度使用索引提示或连接提示。在数据的大小和分布发生一点点变化之后,优化器可能会在下周避免翻转行为。如果您的代码中有太多覆盖,您可能会阻止优化器做得更好!

    【讨论】:

    • 感谢您的具体解释!虽然,考虑到 innoDB 不时更新其统计信息,并且考虑到数据库表的更新/插入频率很高(50 秒),但我观察到一旦它下降到cusp,它就不会轻易回来.我必须明确运行“分析表”,这怎么会发生?
    • 统计信息在分析表、显示表状态或查询 INFORMATION_SCHEMA.TABLES 后更新。因此,您可以每 1 小时或每 10 分钟或任何您想要的时间表执行一次这些语句。更新统计数据的影响很小,但足够大,我不会在每次更新后都这样做。
    猜你喜欢
    • 2013-04-21
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 2016-11-02
    • 2019-05-06
    • 1970-01-01
    • 2014-05-08
    • 2023-03-10
    相关资源
    最近更新 更多