【问题标题】:MySQL not updating information_schema, unless I manually run ANALYZE TABLE `myTable`MySQL 不更新 information_schema,除非我手动运行 ANALYZE TABLE `myTable`
【发布时间】:2019-05-20 04:20:25
【问题描述】:

我需要获取表 (InnoDB) 的最后一个 id(主键),为此我执行以下查询:

SELECT (SELECT `AUTO_INCREMENT` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = 'mySchema' AND `TABLE_NAME` = 'myTable') - 1;

返回错误的 AUTO_INCREMENT。问题是 information_schema 的 TABLES 表没有用当前值更新,除非我运行以下查询:

ANALYZE TABLE `myTable`;

为什么 MySQL 不自动更新 information_schema,我该如何解决这个问题?
运行 MySQL 服务器 8.0.13 X64。

【问题讨论】:

  • 我猜 INNODB 数据库将它保存在其他地方

标签: mysql innodb information-schema mysql-8.0


【解决方案1】:
SELECT * FROM tbl ORDER BY insert_datetime DESC LIMIT 1;

将从“最新”插入的行中获取所有数据。不需要处理AUTO_INCREMENT,不需要使用子查询,不需要ANALYZE,不需要information_schema,一旦你有了id就不需要额外的fetch,等等等等。

是的,您确实需要在用于确定什么是“最新”的列上建立一个索引。是的,id 可以使用,但不应该。 AUTO_INCREMENT 值保证是唯一的,但没有其他。

【讨论】:

    【解决方案2】:

    问:为什么 MySQL 不自动更新 information_schema,我该如何解决这个问题?

    答: InnoDB 将 auto_increment 值保存在内存中,并且不会将其保存到磁盘。

    元数据查询(例如SHOW TABLE STATUS)的行为受innodb_stats_on_metadatainnodb_stats_persistent 变量设置的影响。

    https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_stats_on_metadata

    每次查询元数据时都强制执行 ANALYZE 可能会降低性能。

    除了这些变量的设置,或者通过手动执行ANALYZE TABLE 来强制收集统计数据,我认为没有“修复”这个问题。

    (我认为这主要是因为我认为这不是需要解决的问题。)


    要获取表中某个 auto_increment 列的最大值,规范模式是:

     SELECT MAX(`ai_col`) FROM `myschema`.`mytable`
    

    令我困惑的是为什么我们需要检索这条特定的信息。我们要用它做什么?

    当然,我们不会在应用程序代码中使用它来确定分配给我们刚刚插入的行的值。不能保证最大值不是来自其他会话插入的行。我们有LAST_INSERT_ID() 机制来检索我们会话刚刚插入的行的值。

    如果我们使用ANALYZE TABLE 来刷新统计信息,那么这与随后的SELECT 之间还有一小段时间......另一个会话可能会滑入另一个INSERT,以便我们从收集中获得的值到我们检索它时,统计信息可能已经“过时”了。

    【讨论】:

    • 感谢您的精彩解释。我认为 MAX(id) 可能会减慢查询速度,因此找到了另一种方法,但不幸的是不适用于 InnoDB 表。我的用例如下:我有一个包含空间坐标的表,并且在新插入时,我必须检查新位置是否在 10m 半径范围内。如果是这样,请丢弃该位置。您认为使用这种方法是错误的吗?谢谢!
    • 拥有合适的可用索引应该可以使SELECT MAX(mycol) FROM mytable 的性能合理。用例的唯一问题是有点模糊。我们需要检查我们的新(要插入)行的坐标是否在 ai_col 值最高的行坐标的 10mi 范围内?如果我们必须查询表格以获取坐标,那么我们可以使用类似于SELECT r.coordinate_col FROM mytable r JOIN ( SELECT MAX(t.id) AS max_id FROM mytable t ) s ON s.max_id = r.id 的内容来完成。
    • 如果我们需要计算“如乌鸦飞翔”的大圆距离,我们可以使查询更精细一些,推入我们建议行的坐标,进行 GCD 计算,并返回一段距离……
    • 我会使用 EXPLAIN 来查看查询计划;我会选择 JOINid = (subquery) 模式的内联视图。我们只想确保 MySQL 它启动到距离计算之前将结果缩减为单行,我们只需要在一行上执行此操作。我倾向于做类似的事情:SELECT ST_Distance_Sphere(POINT(?, ?), t.lnglat) <= 10 AS bool_ FROM location t JOIN ( SELECT MAX(r.id) AS max_id FROM location r ) s ON s.max_id = t.id
    • @YanKarin - 如果您使用 ORDER BY id DESC LIMIT 1,则不需要子查询。 (与我的回答类似。)您的查询(和我的变体)将返回真/假(1/0),具体取决于它是否在 10 个距离单位内。 (注意你的单位是什么。)
    猜你喜欢
    • 1970-01-01
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 2023-02-16
    • 2018-12-02
    • 1970-01-01
    相关资源
    最近更新 更多