对于我的网站,我使用 Flickr 的 PHP API ( http://www.flickr.com/services/api/ )。此 API 提供了几种有用的方法来获取特定 GPS 位置周围的照片。
对 API 方法的调用看起来像带有特定参数(如纬度、经度、API key 、半径、排序等)的 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 行,就会出现问题。新的 INSERT
最多需要 2 秒(对于 1,000,000 行最多需要 6 (!) 秒)。
据我所知,问题出在 PRIMARY INDEX 和 InnoDB 引擎上。每次插入新请求时,InnoDB 引擎都会重建树索引并四处移动数据,因为 MD5(request) 是一个真正的随机值。
所以... 问题是有没有更好的方法来缓存这样的请求?或者我应该切换到 MyISAM 引擎?或者我应该尝试伪分区并创建几个表来解决问题?或者可能只是不使用 BTREE 而使用 HASH 索引?
欢迎任何想法!
编辑:
好的,我尝试按照 Furicane 和 Johan 的建议更改表格,但仍然没有成功 - INSERT 最多需要 3 秒。目前 request
字段成为一个普通的非唯一索引,新的 id
列已被添加为具有自动增量的 PRIMARY KEY。我还尝试在此表上添加 4 个分区,结果相同。
我认为 request
字段的索引仍然是一个瓶颈。我目前看到的唯一方法是确定所有可能的参数,将它们作为列添加到表中,然后在它们上创建索引。
还有其他想法吗? :)
编辑 2:
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 在读写方面都名列前茅。也许我的磁盘快死了?如何检查磁盘性能?
最佳答案
InnoDB 不支持 hash
键,只支持 Btree。
MyISAM 因不可靠而臭名昭著。
我认为你的问题是你使用 MD5 值作为主键。
主键包含在每个辅助键中。 并且 PK 被强制为唯一 key 。
设置一个整型自增主键,将你的MD5值设置为普通索引。
它甚至不需要是独一无二的,因为这是让你慢下来的很大一部分原因。
在此之后您的插入应该运行得更快。
关于mysql - 使用随机 PRIMARY KEY 列的值缓慢插入 InnoDB 表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7896534/