【发布时间】: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