【问题标题】:How to improve the performance of table scans with innodb如何使用 innodb 提高表扫描的性能
【发布时间】:2018-05-15 00:36:42
【问题描述】:

简介:有什么方法可以提高对 InnoDB 表的表扫描性能?

请不要建议为避免表扫描添加索引。 (见下文)

innodb_buffer_pool_size 占服务器内存的 75% (48 GB/64GB) 如果有任何改变,我正在使用最新版本的 Percona (5.7.19)

更长:我们有 600Gb 的近期时间序列数据(我们汇总和删除旧数据)分布在 50-60 个表中。因此,其中大部分是定期查询的“活动”数据。这些表有点大(400 多个数字列),许多查询针对其中的一些列(令人担忧)运行,这就是为什么添加索引是不切实际的(因为我们必须添加几十个)。每天对最大的表进行分区。

我完全意识到这是一个应用程序/表设计问题,而不是“服务器调优”问题。我们目前正在努力显着改变这些表的设计和查询方式,但在这种情况发生之前必须维护现有系统,所以我正在寻找一种方法来稍微改进一下,为我们争取一点时间。

我们最近拆分了这个系统,并将其中的一部分移到了新服务器上。它以前使用 MyISAM,我们尝试迁移到 TokuDB,这似乎很合适,但遇到了一些奇怪的问题。我们切换到 InnoDB,但性能真的很差。我的印象是 MyISAM 在表扫描方面更好,这就是为什么除非有更好的选择,否则我们会回到它,直到新系统到位。

更新

所有表的结构几乎相同: -时间戳 -主键(varchar(20) 字段) - 大约 15 个不同类型的字段,代表可以过滤的其他次要属性(以及首先具有适当索引的标准) - 然后大约几百个措施(浮动),在 200-400 之间。

我已经在不改变结构本身的情况下尽可能地修剪了行长。主键曾经是 varchar(100),所有度量值都曾经是双精度数,许多次要属性的数据类型都发生了变化。

升级硬件并不是一个真正的选择。

仅使用我需要的一组列创建小表将有助于加快某些进程的执行速度。但代价是首先使用表扫描创建该表并复制数据。也许如果我将它创建为内存表。据我估计,缓冲池需要几 GB 的空间。还有一些聚合过程会定期从主表中读取尽可能多的数据,并且它们需要所有列。

不幸的是,在我计划在下一个版本中解决的那些查询中有很多重复的工作。每次插入一些行(每半小时)时,警报和聚合过程基本上都会重新处理一整天的数据,而不仅仅是处理新的/更改的数据。

就像我说的,较大的表是分区的,所以通常是对每日分区而不是整个表进行扫描,这是一个小小的安慰。

实施一个系统以将其保存在数据库之外的内存中是可行的,但这将需要对遗留系统和开发工作进行大量更改。不妨把时间花在更好的设计上。

对于与 MyISAM 相同的数据,InnoDB 表要大得多(在我的情况下是 2-3 倍),这一事实确实阻碍了性能。

【问题讨论】:

  • 更快的驱动器。更好的 IO。更好的磁盘缓存。减少行大小。抛弃并非绝对必要的任何和所有列。如果必须,请制作一个更优化查询的表的副本。如您所知,答案是索引。表扫描永远不会很快。如果你真的很努力,它们会变得不那么缓慢。
  • 查询过程中有多少数据?你能更具体地介绍一下结构吗?您可以拥有 only 查询时使用的列的表 A,以及拥有所有数据的表 B。查询表 A 会更快,然后您可以从表 B 中获取 ID 值,这是 JOIN 可以为您做的。
  • 您还可以在某种持久进程中将这些列加载到内存中,该进程不时更新并针对该进程进行查询。如果您正在执行简单的过滤,则扫描内存数组中的几百万个项目非常快,几乎为零时间。由于关系开销、MVCC 问题等原因,在数据库中执行此操作必然会慢很多。
  • 感谢您的建议,即使我不确定我是否可以立即使用它,但它总是有助于激发想法。我用附加信息编辑了我的问题

标签: mysql innodb full-table-scan


【解决方案1】:

MyISAM 在表扫描方面要好一些,因为它比 InnoDB 更紧凑地存储数据。如果您的查询是 I/O 密集型的,那么扫描磁盘上较少的数据会更快。但这是一个相当薄弱的解决方案。

您可以尝试使用 InnoDB 压缩来减少数据大小。这可能会让你更接近 MyISAM 的大小,但你仍然受 I/O 限制,所以它会很糟糕。

最终,听起来您需要一个专为 OLAP 工作负载设计的数据库,例如数据仓库。 InnoDB 和 TokuDB 都是为 OLTP 工作负载而设计的。

【讨论】:

【解决方案2】:

它闻起来像带有“报告”的数据仓库。通过在什么时间段(通常是小时或天)内明智地选择要聚合的内容(从您的浮动中选择),您可以构建和维护汇总表,从而更有效地为报告工作。这具有仅扫描一次数据(以构建摘要)而不是重复扫描的效果。摘要表要小得多,因此报告要快得多——通常是 10 倍。

还可以在插入原始数据时扩充汇总表。 (见INSERT .. ON DUPLICATE KEY UPDATE ..

并使用按日期分区以实现高效的DROP PARTITION 而不是DELETE。分区不要超过 50 个。

Summary Tables

Time series Partitioning

如果您想更详细地讨论,让我们从现在扫描如此之多的查询之一开始。

在我从事的各种项目中,有 2 到 7 个汇总表。

有了 600GB 的数据,您可能会突破“摄取”的限制。如果是这样,我们也可以讨论。

【讨论】:

  • 几个月前我找到了你的网站,我们的很多新设计都基于它。谢谢你写它。一段时间以来,我们一直在使用分区来方便维护、方便查询并提高摄取速度。其他计划中的改进: -对我们的数据使用 MySQL 8 和 JSON。我们收到的措施会定期更改。我们必须每隔几周更换一次表格。 - 为聚合(汇总)保留 SUM 和 COUNT,但为增量方差/标准差保留 MIN、MAX 和 SUM_OF_SQUARES。
  • 另外,将 h... 标准化。这是我们目前设计的一个很大的差距。这将大大减小我们表格的大小。我只是不确定如何将这些建议应用到我们当前的设计中,而无需做大量工作以更好地利用未来的设计成为现实。我只是在寻找我可能忽略的快速获胜来赢得时间......我已经设法减少查询频率以帮助服务器。
  • @Carl - "partitions ..提高摄取速度" -- 请详细说明。这可能是我尚未发现的好处。
  • @Carl - 注意“过度规范化”:不要规范化窄列或具有“连续”值(日期、浮点数等)的列。一般避免规范化您将过滤或排序的内容。
  • @Carl - 我很高兴听到我的网站受到赞赏。 (您是第一个使用 sum_of_squares提及的人。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-24
  • 2018-07-11
  • 2012-12-21
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
相关资源
最近更新 更多