3

我有这个简单的查询:

INSERT IGNORE INTO beststat (bestid,period,rawView) VALUES ( 4510724 , 201205 , 1 ) 

在桌子上:

CREATE TABLE `beststat` (
 `bestid` int(11) unsigned NOT NULL,
 `period` mediumint(8) unsigned NOT NULL,
 `view` mediumint(8) unsigned NOT NULL DEFAULT '0',
 `rawView` mediumint(8) unsigned NOT NULL DEFAULT '0',
 PRIMARY KEY (`bestid`,`period`),
) ENGINE=InnoDB AUTO_INCREMENT=2020577 DEFAULT CHARSET=utf8

完成需要 1 秒。


旁注:实际上并不总是需要 1 秒。有时甚至可以在 0.05 秒内完成。但通常需要 1 秒


该表 (beststat) 目前有~ 500'000条记录,其大小为:40MB。我有4GB RAMinnodb buffer pool size= 104,857,600,其中: Mysql: 5.1.49-3

这是我数据库中唯一的 InnoDB 表(其他是 MyISAM)

ANALYZE TABLE beststat显示:好的

也许 InnoDB 设置有问题?

4

2 回答 2

2

作为客户评估项目的一部分,我在大约 3 年前运行了一些模拟。他们需要能够搜索不断添加数据的表,并且他们希望在一分钟内保持最新状态。

InnoDB 一开始就显示出更好的结果,但很快就恶化了(远在 100 万条记录之前),直到我删除了所有索引(包括主索引)。在这一点上,InnoDB 在执行插入/更新时已经变得优于 MyISAM。(我的硬件比你差得多,只在我的笔记本电脑上执行测试。)

结论:如果你有索引,插入总是会受到影响,尤其是唯一的。

我建议进行以下优化:

  1. 从 beststat 表中删除所有索引并将其用作简单转储。
  2. 如果您真的需要这些唯一索引,请考虑一些可编程解决方案(例如始终记住最大 bestid,并坚持新记录高于该数字 - 并立即增加该数字。(但是您真的需要这么多唯一字段吗?在我看来,它们听起来就像索引一样。)
  3. 让后台线程将新记录从 InnoDB 移动到另一个将被索引的表(可以是 MyISAM)。
  4. 考虑暂时删除索引,然后在批量更新后重新索引表,可能会切换两个表,以便查询永远不会中断。

我承认,这些是理论上的解决方案,但考虑到您的问题,这是我能说的最好的解决方案。

哦,如果您的表计划增长到数百万,请考虑使用 NoSQL 解决方案。

于 2012-05-12T10:23:23.947 回答
1

因此,您在表上有两个唯一索引。您的主键是自动编号。由于在您将其添加到数据中时,这并不是数据的真正一部分,因此您称之为人工主键。现在你有一个关于 bestid 和 period 的唯一索引。如果 bestid 和 period 应该是唯一的,那将是主键的良好候选者。

Innodb 将表存储为树或堆。如果您没有在 innodb 表上定义主键,那么它是一个堆,如果您定义一个主键,它被定义为磁盘上的树。因此,在您的情况下,树基于自动编号键存储在磁盘上。因此,当您创建第二个索引时,它实际上会在磁盘上创建第二个树,其中包含索引中的 bestid 和 period 值。该索引不包含表中的其他列,只有 bestid、period 和你的主键值。

好的,现在您自己插入数据的第一件事就是确保唯一索引始终是唯一的。因此它读取索引以查看您是否尝试插入重复值。这就是减速发挥作用的地方。它首先必须确保唯一性,然后才能通过测试写入数据。然后它还必须将 bestid、周期和主键值插入唯一索引。因此,总操作将是值 1 的 1 个读取索引,将行插入表 1,将 bestid 和周期插入索引。一共三个操作。如果您删除了自动编号并仅使用唯一索引作为主键,如果唯一插入到表中,它将读取表。在这种情况下,您将有以下数量的操作 1 读取表以检查值 1 插入表中。这是两个操作对三个。

I hope this is clear as I am typing from my Android and autocorrect keeps on changing innodb to inborn. Wish I was at a computer.

于 2012-05-12T10:55:17.163 回答