mysql - 使用随机 PRIMARY KEY 列的值缓慢插入 InnoDB 表

标签 mysql primary-key innodb flickr

对于我的网站,我使用 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/

相关文章:

android - 处理键盘上的 Enter 和搜索键

php - 一对一关系/唯一 key 对

mysql - 如何在 MySQL 中索引查找表

c++ - MySQL异步?

php - 控制mysql第一条记录

ms-access - 设置两个字段主键

PHP MySQL 创建转储文件,更改数据库中的所有 PK 和关联的 FK

mysql - 如何让 Navicat mySQL (Non-Commercial) 表默认为 InnoDB 引擎?

php - 对于 Mysql 和 Oracle 表,从 PHP 中的变量将多行插入表中

mysql - Bash - 在 Ubuntu 18 中从 mysql-client 解析中分割字符串的问题