我有一个mysql表,其中有超过3000万条记录最初与myisam一起存储。这是表格的描述:
我会针对此表运行以下查询,通常需要大约30秒才能完成。我每次都会更改@eid以避免数据库或磁盘缓存。
select count(fact_data.id)
from fact_data
where fact_data.entity_id=@eid
and fact_data.metric_id=1
然后我将此表转换为innoDB而不进行任何其他更改,之后相同的查询现在每次运行查询时返回一秒钟。即使我随机设置@eid以避免缓存,查询也会在一秒钟内返回。
我一直在研究两种存储类型之间的差异,试图解释性能的显着改善,但却未能提出任何建议。事实上,我读到的大部分内容都表明Myisam应该更快。
我正在运行的查询是针对本地数据库的,在测试时没有其他进程访问数据库。
答案 0 :(得分:15)
这是一个惊人的巨大性能差异,但我可以想到一些可能有所贡献的事情。
MyISAM历史上被认为比InnoDB更快,但对于最新版本的InnoDB,对于更小,更小的用例集来说也是如此。对于只读表的表扫描,MyISAM通常更快。在大多数其他用例中,我通常发现InnoDB更快。通常快很多倍。在我使用MySQL的大部分时间里,表锁是MyISAM的丧钟。
MyISAM在其密钥缓冲区中缓存索引。也许您已经将密钥缓冲区设置得太小,无法有效地缓存大型表的索引。
MyISAM依赖于OS来缓存OS磁盘缓存中的.MYD文件中的表数据。如果操作系统内存不足,它将开始转储其磁盘缓存。这可能会迫使它继续从磁盘读取。
InnoDB将索引和数据缓存在自己的内存缓冲区中。如果将innodb_flush_method设置为O_DIRECT,则可以告诉操作系统不要使用其磁盘缓存,但OS X不支持此操作。
InnoDB通常在16kb页面中缓冲数据和索引。根据您在查询之间更改@eid值的方式,由于来自先前查询的磁盘读取,它可能已经缓存了一个查询的数据。
确保以相同方式创建索引。使用explain来检查MySQL是否正在使用索引。由于您包含了describe的输出而不是show create table或show indexes from,我无法判断entity_id是否是复合索引的一部分。如果它不是复合索引的第一部分,则不会使用它。
如果您使用的是相对现代版本的MySQL,请在运行查询之前运行以下命令:
设置profiling = 1;
这将打开您的会话的查询分析。运行查询后,运行
显示个人资料;
这将显示可用配置文件的查询列表。我认为它默认保留最后20个。假设您的查询是第一个,请运行:
显示查询1的个人资料;
然后,您将看到运行查询的每个阶段的持续时间。这对于确定什么(例如,表锁定,排序,创建临时表等)导致查询变慢非常有用。
答案 1 :(得分:6)
我的第一个怀疑是原始的MyISAM表和/或索引随着时间的推移而变得碎片化,导致性能慢慢降低。 InnoDB表不会有同样的问题,因为你创建了它已经包含了所有数据(因此它将全部按顺序存储在磁盘上)。
您可以通过重建MyISAM表来测试此理论。最简单的方法是使用" null" ALTER TABLE语句:
ALTER TABLE mytable ENGINE = MyISAM;
然后检查性能以确定它是否更好。
另一种可能性是,数据库本身只是针对InnoDB性能而不是MyISAM进行调整。例如,InnoDB使用innodb_buffer_pool_size parameter
来了解应该分配多少内存来存储内存中的缓存数据和索引。但MyISAM使用key_buffer
参数。如果您的数据库有一个大的innodb缓冲池和一个小的密钥缓冲区,那么InnoDB性能将比MyISAM性能更好,特别是对于大型表。
答案 2 :(得分:1)
您的索引定义是什么,有些方法可以为MyISAM创建索引,在您认为不会使用索引字段时。