【问题标题】:Slow INSERT into InnoDB table with random PRIMARY KEY column's value使用随机 PRIMARY KEY 列的值缓慢插入 InnoDB 表
【发布时间】:2011-12-15 08:12:11
【问题描述】:

对于我的网站,我使用 Flickr 的 PHP API (http://www.flickr.com/services/api/)。此 API 提供了几种有用的方法来获取特定 GPS 位置周围的照片。

对 API 方法的调用看起来像带有特定参数(如纬度、经度、API 密钥、半径、排序等)的 URL。比如说,它看起来像 http://api.flickr.com/method?lat=0.0&lon=0.0&radius=10

我的网站对 API 进行了超过 200,000 次调用,以生成带有来自 Flickr 的图片的多个页面。这是对 API 的一个非常艰难的推动,因此我在 mySQL 数据库中创建了一个结果缓存。

带有缓存的 InnoDB 表的简化方案是:

char(32) request
datetime expires // 2-3 days
text     response // serialized data from API response

其中request 是PRIMARY KEY,表示请求URI 的MD5 散列。其他字段都很简单:)

当表变得足够大(比如超过 100,000 行)时,就会出现问题。新的INSERTs 最多需要 2 秒(1,000,000 行最多需要 6 (!) 秒)。

据我了解,问题在于 PRIMARY INDEX 和引擎是 InnoDB。每次插入新请求时,InnoDB 引擎都会重建树索引并移动数据,因为 MD5(request) 是一个非常随机的值。

所以...问题是是否有更好的方法来缓存此类请求?或者也许我应该切换到 MyISAM 引擎?或者我应该尝试伪分区并创建几个表来解决问题?或者可能只是不使用 BTREE 而是使用 HASH 索引?

欢迎提出任何想法!

编辑:

好的,我尝试按照 Furicane 和 Johan 的建议更改表格,但仍然没有成功 - 插入最多需要 3 秒。目前request 字段成为普通的非唯一索引,并且新的id 列已添加为具有自动增量的主键。我还尝试在此表上添加 4 个分区,结果相同。

我认为request 字段上的索引仍然是一个瓶颈。我目前看到的唯一方法是确定所有可能的参数,将它们作为列添加到表中,然后在它们上创建索引。

还有其他想法吗? :)

编辑 2:

下面 cmets 中的 Salman A 表示,他的类似表的性能要好得多(插入约为 0.03)。这个问题可能出在系统上的 IO 负载中。虽然我不能承受任何高负荷。

iostat 结果:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          22.94    0.71    8.42    8.50    0.00   59.43

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda              38.01       151.04       114.32 1383655437 1047309046

iotop 结果:

Total DISK READ: 152.91 K/s | Total DISK WRITE: 197.67 K/s

mySQL 在写作和阅读方面都位居榜首。也许我的磁盘快死了?如何检查磁盘性能?

【问题讨论】:

  • 不要将该哈希用作主键,使用代理主键 (auto_increment) 并将您的哈希字段定义为唯一键,以避免重复。使用顺序键并且没有 btree 重新平衡,InnoDB 插入相当不错并且可以很好地扩展。
  • 我会试试的,Furican,谢谢。
  • @Furicane:不,还要 2 秒才能插入。详情见原帖:)
  • @WASD42:也可以查看这篇文章了解 InnoDB 设置:mysqlperformanceblog.com/2007/11/01/…
  • 您的磁盘有可能正在死机,尤其是在读取/写入速度如此之低的情况下。搜索率可能也很糟糕。

标签: mysql primary-key innodb flickr


【解决方案1】:

InnoDB 不支持 hash 键,只支持 Btree。

MyISAM 因不可靠而臭名昭著。
我认为您的问题是您使用 MD5 值作为主键。

主键包含在每个辅助键中。 并且 PK 被强制为唯一键。

设置一个整数自增主键并将您的 MD5 值设置为普通索引。
它甚至不需要是独一无二的,因为这是让你慢下来的很大一部分。

在此之后,您的插入应该运行得更快。

【讨论】:

  • 不,还要 2 秒才能插入。详情见原帖:)
  • 是的,问题是您有一个不存储顺序值而是(或多或少)随机值的聚集(主)索引。当插入新行时,作为主键自动递增的整数不会导致重新排列。
猜你喜欢
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多