我正在从事一个涉及大量数据库写入的项目(70%的插入和30%的读取)。这个比率还包括我认为是一个读一个写的更新。读取可能是脏的(例如,在读取时我不需要100%准确的信息)。 该任务每小时将处理超过100万个数据库事务。

我在网上读了一堆关于MyISAM和InnoDB之间区别的东西,对于我将用于这个任务的特定数据库/表来说,MyISAM似乎是显而易见的选择。从我看来,InnoDB在需要事务时是很好的,因为它支持行级锁。

有人有这种负载(或更高)的经验吗?MyISAM是正确的选择吗?


当前回答

几乎每次我开始一个新项目时,我都会问同样的问题,看看我是否能想出新的答案。

它最终归结为——我使用最新版本的MySQL并运行测试。

我有表,我想做键/值查找…就这些。我需要得到一个哈希键的值(0-512字节)。这个数据库上没有很多事务。表偶尔会更新(整个表),但是没有事务。

所以我们这里讨论的不是一个复杂的系统,我们讨论的是一个简单的查找,..以及如何(除了使表RAM常驻)优化性能。

我也在其他数据库(即NoSQL)上做测试,看看是否有任何地方我可以获得优势。我所发现的最大优势是键映射,但就查找而言,MyISAM目前是所有优势中的佼佼者。

虽然,我不会执行与MyISAM表的金融交易,但对于简单的查找,你应该测试它。通常是2倍到5倍的查询/秒。

试试吧,我欢迎辩论。

其他回答

这个问题和大部分答案都已经过时了。

是的,MyISAM比InnoDB快是无稽之谈。注意问题的日期:2008年;现在已经过去了近十年。从那时起,InnoDB在性能上取得了显著的进步。

戏剧性的图表是MyISAM获胜的一种情况:没有where子句的COUNT(*)。但这真的是你花时间做的事情吗?

如果你运行并发测试,InnoDB很可能会赢,即使是对MEMORY。

如果在对select进行基准测试时执行任何写入操作,MyISAM和MEMORY可能会因为表级锁定而丢失。

事实上,Oracle非常确定InnoDB更好,以至于他们几乎从8.0中删除了MyISAM。

这个问题写于5.1的早期。从那时起,这些主要版本被标记为“一般可用性”:

2010: 5.5(。12月8日) 2013: 5.6(。2月10日) 2015年:5.7(。10月9日) 2018年:8.0(。四月十一日)

底线:不要使用MyISAM

有点晚了…但这是我几个月前写的一篇相当全面的文章,详细介绍了MYISAM和InnoDB之间的主要区别。喝杯茶(或者一块饼干),好好享受吧。


MyISAM和InnoDB之间的主要区别在于引用完整性和事务。还有其他区别,如锁定、回滚和全文搜索。

参照完整性

Referential integrity ensures that relationships between tables remains consistent. More specifically, this means when a table (e.g. Listings) has a foreign key (e.g. Product ID) pointing to a different table (e.g. Products), when updates or deletes occur to the pointed-to table, these changes are cascaded to the linking table. In our example, if a product is renamed, the linking table’s foreign keys will also update; if a product is deleted from the ‘Products’ table, any listings which point to the deleted entry will also be deleted. Furthermore, any new listing must have that foreign key pointing to a valid, existing entry.

InnoDB是一个关系DBMS (RDBMS),因此具有引用完整性,而MyISAM没有。

事务和原子性

表中的数据使用数据操作语言(DML)语句进行管理,例如SELECT、INSERT、UPDATE和DELETE。事务将两个或多个DML语句组合到一个工作单元中,因此可以应用整个工作单元,也可以不应用任何工作单元。

MyISAM不支持事务,而InnoDB支持。

如果在使用MyISAM表时操作中断,操作将立即中止,受影响的行(甚至是每行中的数据)仍然受到影响,即使操作没有完成。

如果一个操作在使用InnoDB表时被中断,因为它使用事务,具有原子性,任何没有完成的事务都不会生效,因为没有提交。

表锁vs行锁

当对MyISAM表执行查询时,所查询的整个表将被锁定。这意味着后续查询只会在当前查询完成后执行。如果您正在读取一个大的表,并且/或者有频繁的读和写操作,这可能意味着大量的查询积压。

当对InnoDB表执行查询时,只有涉及的行被锁定,表的其余部分仍可用于CRUD操作。这意味着查询可以在同一个表上同时运行,前提是它们不使用同一行。

这个特性在InnoDB中被称为并发。尽管并发性很好,但对于选择的表范围有一个主要缺点,即在内核线程之间切换时会产生开销,您应该对内核线程设置一个限制,以防止服务器停止。

事务和回滚

当你在MyISAM中运行一个操作时,更改被设置;在InnoDB中,这些更改可以回滚。用于控制事务的最常用命令是COMMIT、ROLLBACK和SAVEPOINT。1. COMMIT -你可以写多个DML操作,但是只有在COMMIT时更改才会被保存。ROLLBACK -你可以放弃任何尚未提交的操作。SAVEPOINT—设置ROLLBACK操作可以回滚到的操作列表中的一个点

可靠性

MyISAM不提供数据完整性——硬件故障、不干净的关机和取消的操作都可能导致数据损坏。这将需要完全修复或重新构建索引和表。

另一方面,InnoDB使用事务日志、双写缓冲区和自动校验和验证来防止损坏。在InnoDB做任何更改之前,它会将事务之前的数据记录到一个名为ibdata1的系统表空间文件中。如果出现崩溃,InnoDB会通过重放这些日志自动恢复。

全文索引

InnoDB直到MySQL 5.6.4版本才支持FULLTEXT索引。在撰写本文时,许多共享主机提供商的MySQL版本仍然低于5.6.4,这意味着InnoDB表不支持FULLTEXT索引。

然而,这并不是使用MyISAM的正当理由。最好换一个支持最新版本MySQL的主机提供商。并不是说使用FULLTEXT索引的MyISAM表不能转换为InnoDB表。

结论

总之,InnoDB应该是您的默认存储引擎选择。在满足特定需求时选择MyISAM或其他数据类型。

我不是数据库专家,也不是凭经验说的。然而:

MyISAM表使用表级锁定。根据您的流量估计,您每秒有接近200个写入操作。有了MyISAM,在任何时候只有其中一项可以进行。您必须确保您的硬件能够跟上这些事务,以避免超时,即单个查询的时间不能超过5毫秒。

这就意味着你需要一个支持行级锁的存储引擎,比如InnoDB。

另一方面,编写几个简单的脚本来模拟每个存储引擎的负载,然后比较结果应该是相当简单的。

请注意,我的正式教育和经验是在甲骨文,而我的MySQL工作完全是个人的,在我自己的时间,所以如果我说的事情是正确的甲骨文,但不是正确的MySQL,我道歉。虽然这两个系统有很多共同点,关系理论/代数是相同的,关系数据库仍然是关系数据库,但仍然有很多差异!!

我特别喜欢(以及行级锁)InnoDB是基于事务的,这意味着你可能会对你的web应用程序的一个“操作”进行多次更新/插入/创建/修改/删除/等等。出现的问题是,如果只有一些更改/操作最终被提交,而其他的没有提交,那么大多数情况下(取决于数据库的具体设计)最终会得到一个数据/结构冲突的数据库。

Note: With Oracle, create/alter/drop statements are called "DDL" (Data Definition) statements, and implicitly trigger a commit. Insert/update/delete statements, called "DML" (Data Manipulation), are not committed automatically, but only when a DDL, commit, or exit/quit is performed (or if you set your session to "auto-commit", or if your client auto-commits). It's imperative to be aware of that when working with Oracle, but I am not sure how MySQL handles the two types of statements. Because of this, I want to make it clear that I'm not sure of this when it comes to MySQL; only with Oracle.

一个基于事务的引擎擅长的例子:

假设我或你在一个网页上注册参加一个免费活动,系统的主要目的之一是只允许最多100人注册,因为这是该活动的座位限制。一旦注册人数达到100人,系统就会禁止更多的注册,至少直到其他人取消。

在这种情况下,可能有一个表用于记录客人(姓名、电话、电子邮件等),另一个表用于跟踪已经注册的客人的数量。因此,我们对一个“事务”有两个操作。现在假设客户信息添加到GUESTS表后,出现了连接丢失或具有相同影响的错误。GUESTS表已更新(插入),但在更新“可用座位”之前,连接已丢失。

现在我们有一个客人添加到客人桌,但可用座位的数量现在是不正确的(例如,值是85,而实际是84)。

当然,有很多方法可以处理这个问题,比如用“客人表中100减去行数”来跟踪可用座位,或者使用一些代码来检查信息是否一致,等等.... 但是对于像InnoDB这样的基于事务的数据库引擎,要么所有的操作都被提交,要么一个都没有。这在很多情况下是有帮助的,但就像我说的,这不是安全的唯一方法,不是(但是,由数据库处理的好方法,而不是由程序员/脚本作者处理)。

这就是“基于事务”在这个上下文中的所有本质含义,除非我遗漏了一些东西——要么整个事务像它应该的那样成功,要么什么都没有改变,因为只做部分更改可能会对数据库造成轻微到严重的混乱,甚至可能破坏它……

但我要再说一遍,这不是避免弄得一团糟的唯一方法。但它是引擎本身处理的方法之一,让您编写代码/脚本,只需要担心“事务是否成功,如果不成功我该做什么(比如重试)”,而不是手动编写代码从数据库外部“手动”检查它,并为此类事件做更多的工作。

最后,关于表锁和行锁的注意事项:

免责声明:关于MySQL,我可能在以下所有方面都是错误的,假设/示例情况是需要研究的,但我可能在MySQL可能导致损坏的确切原因上是错误的。然而,这些例子在一般编程中是非常真实的,即使MySQL有更多的机制来避免这样的事情……

无论如何,我相当自信地同意那些认为一次允许多少个连接不能围绕一个锁定的表工作的人的观点。事实上,多个连接是锁定一个表的全部意义!!这样,其他进程/用户/应用程序就不能通过同时进行更改来破坏数据库。

在同一行上工作的两个或多个连接如何使你的一天变得非常糟糕? 假设有两个进程都希望/需要更新同一行中的相同值,假设因为该行是一次巴士旅行的记录,并且两个进程都同时希望将“riders”或“available_seats”字段更新为“当前值加1”。

让我们假设一下,一步一步来:

进程1读取当前值,假设它是空的,因此到目前为止是“0”。 进程2也读取当前值,它仍然是0。 进程1写入(当前+ 1)即1。 进程2应该写入2,但由于它在进程1写入新值之前读取了当前值,所以它也将1写入到表中。

我不确定两个连接能像这样混合在一起,在第一个人写之前都是阅读……但如果不是,那么我仍然会看到一个问题:

进程1读取当前值,即0。 进程1写入(当前+ 1),即1。 进程2现在读取当前值。但是,当进程1写(更新)时,它还没有提交数据,因此只有同一进程可以读取它更新的新值,而所有其他进程都可以看到旧的值,直到提交。

而且,至少在Oracle数据库中,有隔离级别,我就不浪费时间解释了。这里有一篇关于这个主题的好文章,每个隔离级别都有它的优点和缺点,这将与基于事务的引擎在数据库中的重要性有关……

最后,在MyISAM内部可能会有不同的安全措施,而不是外键和基于事务的交互。首先,事实上整个表都是锁定的,这使得不太可能需要事务/ fk。

And alas, if you are aware of these concurrency issues, yes you can play it less safe and just write your applications, set up your systems so that such errors are not possible (your code is then responsible, rather than the database itself). However, in my opinion, I would say that it is always best to use as many safeguards as possible, programming defensively, and always being aware that human error is impossible to completely avoid. It happens to everyone, and anyone who says they are immune to it must be lying, or hasn't done more than write a "Hello World" application/script. ;-)

我希望其中一些对别人有所帮助,甚至更多,我希望我现在不是假设的罪魁祸首,也不是一个错误的人!!如果是这样的话,我很抱歉,但是这些例子很值得思考,研究风险,等等,即使它们在这个特定的上下文中不是潜在的。

请随意纠正我,编辑这个“答案”,甚至投票否决。请尽量改进,而不是用另一个错误的假设来纠正我的错误假设。: -)

这是我的第一个回应,所以请原谅由于所有的免责声明,等等。我只是不想在不确定的时候显得傲慢!

myisam对于这种类型的工作负载(高并发写入)是一个NOGO,我对innodb没有那么多的经验(测试了3次,发现每次性能都很糟糕,但自从上次测试以来已经有一段时间了) 如果你没有被强迫运行mysql,可以考虑尝试postgres,因为它处理并发写要更好