MyISAM 与 InnoDB

我要说的是一个涉及大量数据库写入的项目( 70%的插入和 30%的读取 )。这个比率还将包括我认为是一次读取和一次写入的更新。读取内容可能很脏(例如,读取时我不需要 100%准确的信息)。
有问题的任务将是每小时进行超过一百万次数据库事务。

我已经在网上阅读了很多有关 MyISAM 和 InnoDB 之间差异的内容,对于我将用于此任务的特定数据库 / 表,MyISAM 似乎是我的明显选择。从我看来,如果需要事务,因为支持行级锁定,因此 InnoDB 很好。

是否有人对这种负载(或更高负载)有任何经验? MyISAM 是要走的路吗?

答案

我已经在一个表中简要讨论了这个问题,因此您可以得出结论,是否要使用InnoDBMyISAM

以下是在哪种情况下应使用哪个数据库存储引擎的简要概述:

MyISAM   InnoDB
----------------------------------------------------------------
Required full-text search                        Yes      5.6.4
----------------------------------------------------------------
Require transactions                                      Yes
----------------------------------------------------------------
Frequent select queries                          Yes      
----------------------------------------------------------------
Frequent insert, update, delete                           Yes
----------------------------------------------------------------
Row locking (multi processing on single table)            Yes
----------------------------------------------------------------
Relational base design                                    Yes

总结一下:

Frequent reading, almost no writing   => MyISAM
Full-text search in MySQL <= 5.5      => MyISAM

在所有其他情况下, InnoDB通常是最好的方法。

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

MyISAM 表使用表级锁定 。根据流量估算,每秒将近 200 次写入。使用 MyISAM, 任何时候都只能进行其中之一 。您必须确保您的硬件可以跟上这些事务,以避免被超载,即,单个查询最多可以花费 5 毫秒。

对我来说,这建议您需要一个支持行级锁定的存储引擎,即 InnoDB。

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

人们经常谈论性能,读取与写入,外键等,但是在我看来,存储引擎还有一个必须具备的功能: 原子更新。

尝试这个:

  1. 对 MyISAM 表发出 UPDATE,耗时 5 秒。
  2. 在进行 UPDATE(例如 2.5 秒钟)时,按 Ctrl-C 中断它。
  3. 观察桌子上的效果。更新了多少行?有多少未更新?该表甚至可读,还是在按 Ctrl-C 时损坏了?
  4. 对 InnoDB 表使用 UPDATE 进行相同的实验,中断正在进行的查询。
  5. 观察 InnoDB 表。 行已更新。 InnoDB 向您保证您拥有原子更新,并且如果无法提交完整更新,它将回滚整个更改。此外,表未损坏。即使使用killall -9 mysqld模拟崩溃,此方法也有效。

当然,性能是可取的,但不会丢失数据应该胜过这一点。

我已经在使用 MySQL 的高容量系统上工作,并且尝试了 MyISAM 和 InnoDB。

我发现 MyISAM 中的表级锁定对我们的工作负载造成了严重的性能问题,这听起来与您的相似。不幸的是,我还发现 InnoDB 的性能也比我希望的要差。

最后,我通过对数据进行分段解决了争用问题,从而使插入数据进入 “热” 表,并选择了从不查询热表。

这还允许在 “陈旧” 表上进行删除(数据是时间敏感的,我们只保留了 X 天的时间),而选择查询仍然没有删除该表。 InnoDB 在批量删除方面的性能似乎很差,因此,如果您打算清除数据,则可能需要以一种方式构造数据,即旧数据位于一个陈旧的表中,可以将其删除而不是对其进行删除。

当然,我不知道您的应用程序是什么,但希望这可以使您对 MyISAM 和 InnoDB 的某些问题有一些了解。

游戏有点晚了... 但是这是我几个月前写的一篇非常全面的文章 ,详细介绍了 MYISAM 和 InnoDB 之间的主要区别。拿起一杯(可能还有饼干),然后享用。


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

参照完整性

参照完整性可确保表之间的关系保持一致。更具体地说,这意味着当表(例如清单)具有指向另一个表(例如产品)的外键(例如产品 ID)时,当指向该表的更新或删除发生时,这些更改将级联到链接表。在我们的示例中,如果产品被重命名,则链接表的外键也会更新。如果从 “产品” 表中删除了产品,则指向已删除条目的所有列表也会被删除。此外,任何新列表都必须具有指向有效的现有条目的外键。

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

交易与原子性

使用数据操作语言(DML)语句(例如 SELECT,INSERT,UPDATE 和 DELETE)来管理表中的数据。一个事务将两个或多个 DML 语句组合在一起成为一个工作单元,因此要么应用整个单元,要么不应用整个单元。

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

如果在使用 MyISAM 表时操作被中断,则该操作将立即中止,并且即使操作未完成,受影响的行(甚至每一行中的数据)仍会受到影响。

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

表锁定与行锁定

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

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

InnoDB 中的此功能称为并发。就并发性而言,最大的缺点是它适用于选定的表范围,因为在内核线程之间进行切换会产生开销,因此您应该对内核线程设置一个限制,以防止服务器停机。

交易和回滚

当您在 MyISAM 中运行操作时,将进行更改。在 InnoDB 中,这些更改可以回滚。用于控制事务的最常见命令是 COMMIT,ROLLBACK 和 SAVEPOINT。 1. COMMIT - 您可以编写多个 DML 操作,但是更改仅在进行 COMMIT 时保存。2. ROLLBACK - 您可以放弃尚未提交的所有操作 3. SAVEPOINT - 在以下列表中设置一个点 ROLLBACK 操作可以回滚到的操作

可靠性

MyISAM 不提供数据完整性 - 硬件故障,不正常关机和取消的操作可能会导致数据损坏。这将需要完全修复或重建索引和表。

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

全文索引

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

但是,这不是使用 MyISAM 的有效理由。最好更改为支持 MySQL 最新版本的托管服务提供商。并不是使用 FULLTEXT 索引的 MyISAM 表不能转换为 InnoDB 表。

结论

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

对于具有更多读写操作的负载,您将从 InnoDB 中受益。因为 InnoDB 提供的是行锁定而不是表锁定,所以SELECT可以是并发的,不仅可以相互并发,而且可以与许多INSERT并发。但是,除非打算使用 SQL 事务,否则请将 InnoDB 提交刷新设置为 2( innodb_flush_log_at_trx_commit )。这给您带来了很多原始性能,否则,当您将表从 MyISAM 移到 InnoDB 时,这些性能会丢失。

另外,请考虑添加复制。这为您提供了一些读取扩展,并且由于您声明读取不必是最新的,因此可以让复制落后一些。只要确保它可以在流量最大的情况下追赶,否则它将永远落后并且永远不会追赶。但是,如果您采用这种方式,我强烈建议您将读取与从属读取隔离,并将复制滞后管理隔离到数据库处理程序。如果应用程序代码不知道这一点,则非常简单。

最后,要注意不同的表加载。您不会在所有表上具有相同的读 / 写比率。一些读取率接近 100%的小桌子可以负担得起 MyISAM。同样,如果有些表的写入率接近 100%,则可以从INSERT DELAYED受益,但这仅在 MyISAM 中受支持(对于 InnoDB 表, DELAYED子句将被忽略)。

但是可以确定基准。

为了增加此处涉及两个引擎之间机械差异的响应的广泛选择,我提出了一个经验速度比较研究。

就纯速度而言,MyISAM 并不总是比 InnoDB 快,但以我的经验,在 PURE READ 工作环境中,它往往要快 2.0 到 2.5 倍。显然,这并不适合所有环境 - 正如其他人所写的那样,MyISAM 缺少事务和外键之类的东西。

我在下面做了一些基准测试 - 我使用 python 进行循环,并使用 timeit 库进行时间比较。出于兴趣,我还包括了内存引擎,尽管它只适用于较小的表(尽管不断超出 MySQL 内存限制,但不断遇到The table 'tbl' is full ,这提供了最佳的性能。我查看的四种选择是:

  1. 香草选择
  2. 计数
  3. 条件选择
  4. 索引和非索引子选择

首先,我使用以下 SQL 创建了三个表

CREATE TABLE
    data_interrogation.test_table_myisam
    (
        index_col BIGINT NOT NULL AUTO_INCREMENT,
        value1 DOUBLE,
        value2 DOUBLE,
        value3 DOUBLE,
        value4 DOUBLE,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8

在第二个和第三个表中用 “MyISAM” 代替 “InnoDB” 和 “内存”。

1)香草选择

查询: SELECT * FROM tbl WHERE index_col = xx

结果: 平局

不同数据库引擎对香草选择的比较

它们的速度大致相同,并且所期望的要选择的列数是线性的。 InnoDB 的快于 MyISAM 数据似乎但这的确是微不足道的。

码:

import timeit
import MySQLdb
import MySQLdb.cursors
import random
from random import randint

db = MySQLdb.connect(host="...", user="...", passwd="...", db="...", cursorclass=MySQLdb.cursors.DictCursor)
cur = db.cursor()

lengthOfTable = 100000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)
    cur.execute(insertString3)

db.commit()

# Define a function to pull a certain number of records from these tables
def selectRandomRecords(testTable,numberOfRecords):

    for x in xrange(numberOfRecords):
        rand1 = randint(0,lengthOfTable)

        selectString = "SELECT * FROM " + testTable + " WHERE index_col = " + str(rand1)
        cur.execute(selectString)

setupString = "from __main__ import selectRandomRecords"

# Test time taken using timeit
myisam_times = []
innodb_times = []
memory_times = []

for theLength in [3,10,30,100,300,1000,3000,10000]:

    innodb_times.append( timeit.timeit('selectRandomRecords("test_table_innodb",' + str(theLength) + ')', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('selectRandomRecords("test_table_myisam",' + str(theLength) + ')', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('selectRandomRecords("test_table_memory",' + str(theLength) + ')', number=100, setup=setupString) )

2)计数

查询: SELECT count(*) FROM tbl

结果: MyISAM 获胜

比较不同数据库引擎的计数

这证明了 MyISAM 和 InnoDB 之间的巨大区别 - MyISAM(和内存)跟踪表中的记录数,因此该事务处理速度很快,且 O(1)。在我研究的范围内,InnoDB 计数所需的时间随着表的大小而呈超线性增加。我怀疑在实践中观察到的许多 MyISAM 查询的提速是由于类似的影响。

码:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to count the records
def countRecords(testTable):

    selectString = "SELECT count(*) FROM " + testTable
    cur.execute(selectString)

setupString = "from __main__ import countRecords"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('countRecords("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('countRecords("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('countRecords("test_table_memory")', number=100, setup=setupString) )

3)条件选择

查询: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

结果: MyISAM 获胜

不同数据库引擎的条件选择比较

在这里,MyISAM 和内存的性能大致相同,对于较大的表,它们的性能比 InnoDB 高出 50%。这种查询似乎使 MyISAM 的好处最大化。

码:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to perform conditional selects
def conditionalSelect(testTable):
    selectString = "SELECT * FROM " + testTable + " WHERE value1 < 0.5 AND value2 < 0.5 AND value3 < 0.5 AND value4 < 0.5"
    cur.execute(selectString)

setupString = "from __main__ import conditionalSelect"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('conditionalSelect("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('conditionalSelect("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('conditionalSelect("test_table_memory")', number=100, setup=setupString) )

4)子选择

结果: InnoDB 获胜

对于此查询,我为子选择创建了一组附加表。每行仅是两列 BIGINT,一列具有主键索引,一列不具有任何索引。由于表很大,所以我没有测试内存引擎。 SQL 表创建命令为

CREATE TABLE
    subselect_myisam
    (
        index_col bigint NOT NULL,
        non_index_col bigint,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8;

在第二个表中,再次用 “MyISAM” 代替 “InnoDB”。

在此查询中,我将选择表的大小保留为 1000000,而是更改了子选择列的大小。

不同数据库引擎对子选择的比较

在这里,InnoDB 轻松获胜。到达合理的尺寸表后,两个引擎都随子选择的尺寸线性缩放。索引加快了 MyISAM 命令的速度,但有趣的是对 InnoDB 的速度影响很小。 subSelect.png

码:

myisam_times = []
innodb_times = []
myisam_times_2 = []
innodb_times_2 = []

def subSelectRecordsIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString = "from __main__ import subSelectRecordsIndexed"

def subSelectRecordsNotIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT non_index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString2 = "from __main__ import subSelectRecordsNotIndexed"

# Truncate the old tables, and re-fill with 1000000 records
truncateString = "TRUNCATE test_table_innodb"
truncateString2 = "TRUNCATE test_table_myisam"

cur.execute(truncateString)
cur.execute(truncateString2)

lengthOfTable = 1000000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)

for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE subselect_innodb"
    truncateString2 = "TRUNCATE subselect_myisam"

    cur.execute(truncateString)
    cur.execute(truncateString2)

    # For each length, empty the table and re-fill it with random data
    rand_sample = sorted(random.sample(xrange(lengthOfTable), theLength))
    rand_sample_2 = random.sample(xrange(lengthOfTable), theLength)

    for (the_value_1,the_value_2) in zip(rand_sample,rand_sample_2):
        insertString = "INSERT INTO subselect_innodb (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"
        insertString2 = "INSERT INTO subselect_myisam (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)

    db.commit()

    # Finally, time the queries
    innodb_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString) )

    innodb_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString2) )
    myisam_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString2) )

我认为所有这一切的基本含义是,如果您真的关心速度,则需要对正在执行的查询进行基准测试,而不是对哪种引擎更合适进行任何假设。

稍微偏离主题,但出于文档目的和完整性考虑,我想添加以下内容。

通常,使用 InnoDB 会导致更少的复杂应用程序,而且可能也没有更多错误。因为您可以将所有参照完整性(外键约束)放入数据模型,所以您不需要像 MyISAM 那样需要那么多应用程序代码。

每次插入,删除或替换记录时,您都必须检查和维护关系。例如,如果您删除父母,则所有孩子也应被删除。例如,即使在简单的博客系统中,如果您删除博客发布记录,也将必须删除评论记录,类似消息等。在 InnoDB 中,这是由数据库引擎自动完成的(如果您在模型中指定了约束, ),不需要任何应用代码。在 MyISAM 中,必须将其编码到应用程序中,这在 Web 服务器中非常困难。 Web 服务器本质上是非常并行 / 并行的,并且由于这些操作应该是原子性的,并且 MyISAM 不支持任何实际事务,因此将 MyISAM 用于 Web 服务器是有风险 / 容易出错的。

在大多数情况下,由于多种原因,InnoDB 的性能也会好得多,其中一个原因是,他们能够使用记录级锁定而不是表级锁定。不仅在写入比读取更频繁的情况下,还在大型数据集上具有复杂联接的情况下。我们注意到,对于非常大的联接(耗时数分钟),仅使用 InnoDB 表而不是 MyISAM 表可将性能提高 3 倍。

我要说的是,通常,在使用 MySQL 时,InnoDB(使用具有参照完整性的 3NF 数据模型)应该是默认选择。 MyISAM 仅应在非常特殊的情况下使用。它最有可能表现不佳,导致应用程序更大,更富 bug。

话虽如此。数据建模是网页设计师 / 程序员中很少发现的艺术。没有违法,但这确实解释了 MyISAM 被如此广泛地使用。

InnoDB 提供:

ACID transactions
row-level locking
foreign key constraints
automatic crash recovery
table compression (read/write)
spatial data types (no spatial indexes)

在 InnoDB 中,除了 TEXT 和 BLOB 之外,一行中的所有数据最多可以占用 8,000 个字节。 InnoDB 没有全文索引。在 InnoDB 中,COUNT(*)(不使用 WHERE,GROUP BY 或 JOIN 时)的执行速度比 MyISAM 慢,这是因为行计数不是内部存储的。 InnoDB 将数据和索引都存储在一个文件中。 InnoDB 使用缓冲池来缓存数据和索引。

MyISAM 提供:

fast COUNT(*)s (when WHERE, GROUP BY, or JOIN is not used)
full text indexing
smaller disk footprint
very high table compression (read only)
spatial data types and indexes (R-tree)

MyISAM 具有表级锁定,但没有行级锁定。没有交易。没有自动崩溃恢复,但是它确实提供了修复表功能。没有外键约束。与 InnoDB 表相比,MyISAM 表在磁盘上的大小通常更紧凑。如果需要,可以通过使用 myisampack 进行压缩来进一步高度减小 MyISAM 表的大小,但该表将变为只读状态。 MyISAM 将索引存储在一个文件中,将数据存储在另一个文件中。 MyISAM 使用键缓冲区来缓存索引,并将数据缓存管理留给操作系统。

总的来说,我会建议将 InnoDB 用于大多数用途,并将 MyISAM 仅用于特殊用途。现在,InnoDB 是新 MySQL 版本中的默认引擎。

如果使用 MyISAM,则不会每小时进行任何事务,除非您将每个 DML 语句都视为事务(无论如何,如果发生崩溃,它将不会持久或原子)。

因此,我认为您必须使用 InnoDB。

每秒 300 个事务听起来很多。如果您绝对需要这些事务在断电时能够持久运行,请确保您的 I / O 子系统每秒可以轻松处理这么多的写入。您将至少需要一个具有电池后备缓存的 RAID 控制器。

如果可以减少耐用性,则可以将 Innodb_flush_log_at_trx_commit 设置为 0 或 2(请参阅文档以了解详细信息)来使用 InnoDB,可以提高性能。

有许多补丁程序可以提高 Google 和其他公司的并发性 - 如果没有它们您仍然无法获得足够的性能,这些补丁程序可能会很有趣。