在mysql / innodb中拥有超过500M varchar(255)记录的唯一密钥的最佳方法是什么?

时间:2010-03-12 22:55:55

标签: mysql

我的url列上有唯一键 - 但它在更新时的表现绝对是残酷的。我怀疑那是因为索引并不适合记忆。

所以我在思考,如何添加一个md5(url)列,其中包含16个字节的二进制数据和唯一键控。

最好的数据类型是什么?我希望能够只看到32个字符的十六进制哈希值,而mysql会将它转换为16个二进制字节并将其转换为索引,因为使用数据库的程序可能会遇到任意二进制数据的麻烦,我宁愿避免如果可能的话(我也有点害怕mysql可能会得到一些关于字符集的奇怪想法,例如3:1因为它认为它可能需要utf8,因此我可以避免这种情况用于治疗?)。< / p>

似乎某种解决方案是binary(16) null用于存储,unhex(md5(url))用于插入/比较,hex(url_hash)用于检索(不是它确实需要检索,将会有未编入索引{{}无论如何1}}列。这是最好的方式吗?

4 个答案:

答案 0 :(得分:4)

MD5无法保证唯一,因此您无法在其上创建唯一索引,除非您的商业模式允许您在碰撞时拒绝插入和更新。是这样的吗?我问,因为从性能的角度来看,解决冲突(无论多么不可能)将会非常复杂。

在任何情况下,我都很难相信(不是说它可能不是真的)一个结构合理的查询,MySQL正确规划使用正确的索引(甚至超过500M行),必须遭受恶劣的表现 - 但是如果不知道你的查询是什么样的以及你的数字是什么,那么很难再说出来。

如果我是你,在考虑对现有索引查找的解决方法(例如MD5方法)之前,我会确定我的问题真正存在的地方:

  • 使用EXPLAIN确认您的UPDATE语句确实使用了正确的索引
    • 您不能EXPLAIN UPDATE语句,但您可以EXPLAIN其等效SELECT语句(您基本上关心WHERE子句,{{1等等。)
    • 即使有500M行,JOIN索引每个匹配行只需要少量页面
      • 您希望每个btree语句更新多少行?实际更新了多少行?
      • 除了UPDATE之外,您的WHERE条款还有其他条件吗?规划人员可以先选择选择性较低的索引,然后重新启动缓存 - 从url=计划
      • 中查找
    • 当您实际运行(而不是EXPLAIN)时:EXPLAIN系统地比相应的UPDATE慢吗?您可能遇到写入瓶颈,可能是由于锁定问题。慢SELECT时有多少会话处于活动状态?您桌面上定义的索引包含UPDATE列?
    • 最近有你analyzed你的桌子吗?

所以无论如何,在继续之前,请告诉我们:

  • 你在批量url吗?每秒UPDATE秒(或每UPDATE多少毫秒)会满足您的性能要求多少?
  • UPDATE
  • 时有多少会话处于活动状态
  • 你分析了你的桌子吗?
  • 什么是UPDATE示例查询? (请提供其参数的具体值)
  • 相应UPDATE的解释计划是什么? (使用相同的具体值)
  • 相应的SELECT(使用相同的特定值)在执行时实际需要多长时间才能完成(不是SELECT ed),以及它实际返回了哪些行?
  • 执行时实际EXPLAIN(使用相同的特定值)需要多长时间? (不是UPDATE ed)

答案 1 :(得分:0)

我并不特别熟悉MySQL - 但我的猜测是,唯一索引是一个聚簇索引(意味着数据页是与它一起订购的)。更新时,会导致重组整个表。

如果您可以将聚集索引移动到某个稳定值,那么这应该可以解决您的问题。

答案 2 :(得分:0)

如果您只使用索引来保证唯一性而不是检索,那么在binary(16) not null列中使用MD5可能是一个胜利。这样,您可能在索引页面中拥有数百个密钥,从而减少了每个插入的磁盘搜索次数。

另一种方法是在表格中使用压缩,方法如下:

CREATE TABLE foo (url varchar(255)) ENGINE=InnoDB
ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;

由于网址应该压缩得非常好,因此它可能与您的哈希创意一样大,而且不需要任何额外的代码。

以下是关于压缩的InnoDB参考:http://www.innodb.com/doc/innodb_plugin-1.0/innodb-compression.html

答案 3 :(得分:-2)

索引可能已经使用哈希,比你手工制作的MD5解决方案更有效。

相关问题