【问题标题】:A simple INSERT query on InnoDB taking too muchInnoDB 上的简单 INSERT 查询占用太多
【发布时间】:2012-05-12 10:04:14
【问题描述】:

我有一个简单的查询:

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 设置有问题?

【问题讨论】:

  • 请尝试REPLACE INTO beststat (bestid,period,rawView) VALUES (x,y,z) 获取 x,y 的碰撞值,INSERT INTO beststat (bestid,period,rawView) VALUES (x,y,z) 获取 x,y 的非碰撞值-显然确保您不会破坏任何有价值的东西-并发布结果以进行比较
  • 你是如何测量插入速度的?
  • 您确定没有其他进程/线程占用大量 CPU 时间吗?
  • @SoboLAN:我运行了更多查询,并且仅在此表上进行这样的查询 innodb 需要这么多

标签: mysql sql performance innodb


【解决方案1】:

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

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

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

我建议进行以下优化:

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

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

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

【讨论】:

  • Strnage 我在 Innodb 上运行了几个数据库,其中包含超过 500 000 000 条记录并且没有问题。删除主键有利于写入速度,但不利于读取速度。 NoSQL 替代方案可能合适,但也可能不合适。
  • 删除唯一键不是一个很好的建议。您将花费更多时间来修复重复项,而不是在插入期间保存。对于现代硬件上的任何现代 RDBMS,数百万行应该不是问题。
  • 好的,我同意我的回答不够通用,但它对我有用(十亿条记录,每天百万条插入,没有重复问题,每小时完成批量处理)。我想要获得确切的解决方案,需要更多有关问题的信息。
  • 我不认为我可以在上面做任何事情:(
【解决方案2】:

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

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

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

我希望这很清楚,因为我是从我的 Android 输入的,并且自动更正不断将 innodb 更改为先天。希望我在电脑前。

【讨论】:

  • 我可以试试!我将删除那个无用的 id 字段。但它仍然不应该花这么多。
  • 这会减少工作量,但不要指望它会快几光年。可能还有其他问题,例如磁盘驱动器争用,这可能会减慢您的速度。至少这样你会更有效率。
  • 已删除。现在桌子的大小是以前的一半!现在是 32MB。这就是一个很好的结果。希望现在查询更快
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
相关资源
最近更新 更多