【问题标题】:Counting records in mysql innodb table计算mysql innodb表中的记录
【发布时间】:2016-08-13 03:47:16
【问题描述】:

我正在使用带有 innodb 的 mysql 在 Rails 中开发一个应用程序。我需要经常获取全表计数,并且我知道使用 innodb,计算表中的所有记录可能会非常昂贵,因为它需要全表扫描。我正在查看 rails 控制台中的一个典型表,并查看查询时间以计算记录。到目前为止,我发现第一次计算记录需要很长时间,但在随后的尝试中速度要快得多。例如:

2.2.2 :002 > Request.count
   (683.7ms)  SELECT COUNT(*) FROM `requests`
 => 260588
2.2.2 :003 > Request.count
   (47.6ms)  SELECT COUNT(*) FROM `requests`
 => 260588
2.2.2 :004 > Request.count
   (46.7ms)  SELECT COUNT(*) FROM `requests`
 => 260588

那么,首先,我什至需要担心优化这个结果吗?也许计数正在被 Rails 或 mySql 或 InnoDB 缓存,没有什么可担心的。

我将假设在多个用户在任何给定时间写入表的生产环境中仍然存在一些问题。在这种情况下,我如何“重置”缓存或任何让我对计数时间产生不切实际的乐观看法的东西,以便我可以做一些诚实的基准测试?我试过写记录,或者只是用reload!重新加载控制台,但我从来没有得到最初的长时间。我敢打赌,如果我退出控制台并重新启动 mysql 就可以了,但我宁愿不必那么努力。

最后,我听说像下面这样的查询会运行得更快:

select count(*) from requests use index(<index_name>);

似乎最自然的索引是id 字段。

select count(*) from service_requests use index(id)

但这给了我以下错误:

ERROR 1176 (42000): Key 'id' doesn't exist in table 'requests'

但 id 不仅仅是一个键,它还是主键。在某些表上,它是唯一的索引。为什么 id 不被视为键?

【问题讨论】:

    标签: mysql ruby-on-rails innodb


    【解决方案1】:

    要优化它,请运行 optimize table,然后您可以创建另一个不是主键的索引,因为 InnoDB 使用聚集的主键。

    创建另一个索引时,您必须在另一个易于扫描的字段上创建它,而不是像文本字段这样的东西(如果它适用于请求)。

    错误 - 如果您继续使用主键而不是出于任何原因创建另一个索引:

    正如您提到的那样,主键确实是id,然后在id 上使用use index(id)(查询来自您的表中的PK)将不起作用,它将是USE INDEX (PRIMARY)。要查看该表的其他索引,请运行SHOW INDEX FROM &lt;Table&gt; 命令,这将显示该表的其他索引名称。

    更多信息: http://dev.mysql.com/doc/refman/5.7/en/optimize-table.html http://dev.mysql.com/doc/refman/5.7/en/index-hints.html

    【讨论】:

    • 你也可以使用 FORCE INDEX (PRIMARY)
    【解决方案2】:
    • 不要在 InnoDB 表上运行 OPTIMIZE TABLE;它几乎从未提供任何改进。
    • 请勿使用USE INDEXFORCE INDEX,除非是万不得已。它今天可能对你有所帮助,但明天可能会使事情变得更糟。 Optimize 会动态选择“最佳”索引,它的选择通常是“正确的”。
    • PRIMARY KEY 可能是用于完整表 COUNT(*) 的最差索引。
    • SELECT COUNT(*) 需要时间(对于 InnoDB),因为它必须扫描整个表,绕过任何正在进行的事务。
    • 这样的扫描将选择“最小”索引,因此创建INDEX(foo) 可能会有所帮助,其中foo 是一些小列。但是,这不太可能使速度提高一倍以上。
    • "684s, 47s, 47s" -- 可能第一个请求没有找到缓存在 RAM 中的所有数据,必须从磁盘中获取。由于缓存,第 2 次和第 3 次要快得多。
    • 将 mysql 的 innodb_buffer_pool_size 配置为 可用 RAM 的 70% 左右,以减少 I/O。
    • 如果results 中的行数太多以至于“时间过长”,那么这个数字可能毫无意义。请注意,一些搜索引擎不再说“1,234,566 个结果中的 10 个”甚至“大约 1,000,000 个结果中的 10 个”。那是因为他们发现它不值得计算甚至估计。
    • 因此,下一步(假设您不愿意摆脱计数)是想出某种方法来估计缓存计数。李>
    • 如果您 SELECTWHERE 子句,那么我的大部分回答都不适用。

    【讨论】:

      猜你喜欢
      • 2012-09-13
      • 2014-04-08
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 2012-09-12
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多