在mysql innodb表

时间:2016-08-09 21:39:41

标签: mysql ruby-on-rails innodb

我正在使用带有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不被认为是关键?

2 个答案:

答案 0 :(得分:1)

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

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

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

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

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

答案 1 :(得分:0)

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