简体   繁体   English

Mysql中Innodb和Myisam之间的性能差异

[英]Performance difference between Innodb and Myisam in Mysql

I have a mysql table with over 30 million records that was originally being stored with myisam. 我有一个mysql表,其中有超过3000万条记录最初与myisam一起存储。 Here is a description of the table: 这是表格的描述:

describe_table

I would run the following query against this table which would generally take around 30 seconds to complete. 我将针对此表运行以下查询,通常需要大约30秒才能完成。 I would change @eid each time to avoid database or disk caching. 我每次都会更改@eid以避免数据库或磁盘缓存。

select count(fact_data.id) 
    from fact_data 
    where fact_data.entity_id=@eid 
        and fact_data.metric_id=1

I then converted this table to innoDB without making any other changes and afterwards the same query now returns in under a second every single time I run the query. 然后我将此表转换为innoDB而不进行任何其他更改,之后相同的查询现在每次运行查询时返回一秒钟。 Even when I randomly set @eid to avoid caching, the query returns in under a second. 即使我随机设置@eid以避免缓存,查询也会在一秒钟内返回。

I've been researching the differences between the two storage types to try to explain the dramatic improvement in performance but haven't been able to come up with anything. 我一直在研究这两种存储类型之间的差异,试图解释性能的显着改善,但却未能提出任何建议。 In fact, much of what I read indicates that Myisam should be faster. 事实上,我读到的大部分内容都表明Myisam应该更快。

The queries I'm running are against a local database with no other processes hitting the database at the time of the tests. 我正在运行的查询是针对本地数据库的,在测试时没有其他进程访问数据库。

That's a surprisingly large performance difference, but I can think of a few things that may be contributing. 这是一个惊人的巨大性能差异,但我可以想到一些可能有所贡献的事情。

MyISAM has historically been viewed as faster than InnoDB, but for recent versions of InnoDB, that is true for a much, much smaller set of use cases. MyISAM在历史上被视为比InnoDB更快,但对于InnoDB的最新版本,对于更小,更小的用例集来说也是如此。 MyISAM is typically faster for table scans of read-only tables. 对于只读表的表扫描,MyISAM通常更快。 In most other use cases, I typically find InnoDB to be faster. 在大多数其他用例中,我通常发现InnoDB更快。 Often many times faster. 通常快很多倍。 Table locks are a death knell for MyISAM in most of my usage of MySQL. 在我使用MySQL的大部分时间里,表锁是MyISAM的丧钟。

MyISAM caches indexes in its key buffer. MyISAM在其密钥缓冲区中缓存索引。 Perhaps you have set the key buffer too small for it to effectively cache the index for your somewhat large table. 也许您已经将密钥缓冲区设置得太小,无法有效地为您的大型表缓存索引。

MyISAM depends on the OS to cache table data from the .MYD files in the OS disk cache. MyISAM依赖于OS来缓存OS磁盘缓存中的.MYD文件中的表数据。 If the OS is running low on memory, it will start dumping its disk cache. 如果操作系统内存不足,它将开始转储其磁盘缓存。 That could force it to keep reading from disk. 这可能会迫使它继续从磁盘读取。

InnoDB caches both indexes and data in its own memory buffer. InnoDB将索引和数据缓存在自己的内存缓冲区中。 You can tell the OS not to also use its disk cache if you set innodb_flush_method to O_DIRECT, though this isn't supported on OS X. 如果将innodb_flush_method设置为O_DIRECT,则可以告诉操作系统不要使用其磁盘缓存,但OS X不支持此操作。

InnoDB usually buffers data and indexes in 16kb pages. InnoDB通常在16kb页面中缓冲数据和索引。 Depending on how you are changing the value of @eid between queries, it may have already cached the data for one query due to the disk reads from a previous query. 根据您在查询之间更改@eid值的方式,由于来自先前查询的磁盘读取,它可能已经缓存了一个查询的数据。

Make sure you created the indexes identically. 确保以相同方式创建索引。 Use explain to check if MySQL is using the index. 使用explain来检查MySQL是否正在使用索引。 Since you included the output of describe instead of show create table or show indexes from, I can't tell if entity_id is part of a composite index. 由于您包含了describe的输出而不是show create table或show indexes from,我无法判断entity_id是否是复合索引的一部分。 If it was not the first part of a composite index, it wouldn't be used. 如果它不是复合索引的第一部分,则不会使用它。

If you are using a relatively modern version of MySQL, run the following command before running the query: 如果您使用的是相对现代版本的MySQL,请在运行查询之前运行以下命令:

set profiling = 1; set profiling = 1;

That will turn on query profiling for your session. 这将打开您的会话的查询分析。 After running the query, run 运行查询后,运行

show profiles; 显示档案;

That will show you the list of queries for which profiles are available. 这将显示可用配置文件的查询列表。 I think it keeps the last 20 by default. 我认为它默认保留最后20个。 Assuming your query was the first one, run: 假设您的查询是第一个,请运行:

show profile for query 1; 显示查询1的配置文件;

You will then see the duration of each stage in running your query. 然后,您将看到运行查询的每个阶段的持续时间。 This is extremely useful for determining what (eg, table locks, sorting, creating temp tables, etc.) is causing a query to be slow. 这对于确定什么(例如,表锁,排序,创建临时表等)导致查询变慢非常有用。

My first suspicion would be that the original MyISAM table and/or indexes became fragmented over time resulting in the performance slowly degrading. 我的第一个怀疑是原始的MyISAM表和/或索引随着时间的推移变得支离破碎,导致性能慢慢降低。 The InnoDB table would not have the same problem since you created it with all the data already in it (so it would all be stored sequentially on disk). InnoDB表不会有同样的问题,因为你创建了它已经包含了所有数据(因此它将全部按顺序存储在磁盘上)。

You could test this theory by rebuilding the MyISAM table. 你可以通过重建MyISAM表来测试这个理论。 The easiest way to do this would be to use a "null" ALTER TABLE statement: 最简单的方法是使用“null”ALTER TABLE语句:

ALTER TABLE mytable ENGINE = MyISAM;

Then check the performance to see if it is better. 然后检查性能以确定它是否更好。

Another possibility would be if the database itself is simply tuned for InnoDB performance rather than MyISAM. 另一种可能性是,数据库本身只是针对InnoDB性能而不是MyISAM进行调整。 For example, InnoDB uses the innodb_buffer_pool_size parameter to know how much memory should be allocated for storing cached data and indexes in memory. 例如,InnoDB使用innodb_buffer_pool_size parameter来知道应该分配多少内存来存储内存中的缓存数据和索引。 But MyISAM uses the key_buffer parameter. 但MyISAM使用key_buffer参数。 If your database has a large innodb buffer pool and a small key buffer, then InnoDB performance is going to be better than MyISAM performance, especially for large tables. 如果您的数据库有一个大的innodb缓冲池和一个小的密钥缓冲区,那么InnoDB性能将比MyISAM性能更好,特别是对于大型表。

您的索引定义是什么,有些方法可以为MyISAM创建索引,在这些索引中您的索引字段将不会被使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM