Ama*_*rus 3 mysql innodb performance index
我有一个 Django Web 应用程序,它在 MySQL InnoDB 数据库中存储数据。在 django admin 上有一个特定页面被大量访问,并且查询需要很长时间(~20 秒)。由于它是 Django 内部结构,因此无法更改查询。
有 3 个表A
,B
、 和C
。查询如下所示:
SELECT *
FROM A
INNER JOIN B ON (A.b_id = B.foo)
INNER JOIN C ON (B.foo = C.id)
ORDER BY A.id DESC
LIMIT 100
Run Code Online (Sandbox Code Playgroud)
一个简单的 join-3-tables 在一起。
这些id
字段是主键并具有索引。A.b_id
,B.foo
两者都有自己的索引。
然而,查询计划看起来不对,并说它没有在 B 上使用任何键(但它正在使用其他连接的键)。从阅读大量 MySQL 性能资料来看,理论上应该使用索引,因为它是各种可能“失败”的 const 连接。它说它必须扫描所有大约 1,200 行 B。
奇怪的是,我OPTIMIZE
在本地机器上编辑了每个查询并重新运行查询(使用SQL_NO_CACHE
),它快得多,0.02 秒与原始 20 秒。EXPLAIN
在同一个查询上给出了不同的、更合理的结果,表明它可以在每个查询上使用一个索引,并且它不必扫描整个批次。一位同事OPTIMIZE
在测试机器上用大致相同的数据(最近从加载的转储文件中重新创建)为每个人运行,并且还显示速度增加,并且解释合理。
所以我们在实时系统上运行它......它没有改变任何东西(速度或解释)。我重新创建了我的 MySQL 数据库(DROP
编辑了数据库并从转储中重新加载),现在OPTIMIZE
没有改变任何东西(即~20 秒的运行时间,错误的查询计划)。
为什么会发生这种情况?如何让 MySQL 使用正确的索引并取回 0.02 秒的查询时间?这篇博文(http://www.xaprb.com/blog/2010/02/07/how-often-should-you-use-optimize-table/)暗示OPTIMIZE
只有真正优化主键(不是那个b_id
,foo
是不是主要索引)。如何“重建二级索引”?我尝试过ALTER TABLE A ENGINE=InnoDB
(对于 B 和 C 也是如此),但没有任何变化。
实际上,我越看这个,它似乎就越是 MySQL 查询计划失败。它正在执行错误的查询计划,并且没有使用它可以使用的索引。在执行了 OPTIMIZE TABLE 等操作后,有时可以使用正确的索引。当有这样一个糟糕的查询计划时,它可能会被随机选择,这就是为什么(我认为)不同的机器有不同的结果。
OPTIMIZE 重建表。这(对于 InnoDB)挤出了一些碎片和浪费的空间。这不太可能在任何查询中产生显着差异。
此外,OPTIMIZE 会进行 ANALYZE。这有可能改变统计数据,从而导致不同(更好或更差)的 EXPLAIN 计划。
由于 ANALYZE(在 InnoDB 上)比 OPTIMIZE 快得多,只需执行 ANALYZE。
各种非 ANALYZE 操作会导致执行 ANALYZE。
ANALYZE 随机探测 BTree,收集统计数据。有时,由此产生的统计数据很差。实际上没有办法防止这种情况发生。多年来已经创建了几个部分黑客;5.6.7 使用 ANALYZE 接近消除这个问题。这是其中之一:http : //dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html#sysvar_innodb_stats_persistent_sample_pages