优化 MySQL 中的 hash 搜索

Posted

技术标签:

【中文标题】优化 MySQL 中的 hash 搜索【英文标题】:Optimize search by hash in MySQL 【发布时间】:2013-09-30 10:51:42 【问题描述】:

我有一个包含很多字段的 InnoDB 表,其中一个是 32 字节的唯一哈希(典型的 md5 结果)。

我必须通过该哈希进行大量查询,但我的表开始变大(500.000 条记录),并且此搜索需要很多时间:

SELECT id FROM `table` WHERE `key`='Bj8DzS7RmCG41nLdgOp0kEhNtrfPo3KF'

这花了大约 0.7 秒

我可以创建这个“散列”32 字节 varchar 列的索引,但是这个表增长了很多,如果我必须优化表(重新索引),它需要很多时间来做(大约在我的情况下为 10 分钟),锁定所有其他实时查询。

那么,在必须通过 32 字节 varchar 字段进行搜索的情况下,优化查询的最佳方法是什么?

【问题讨论】:

我不明白你为什么要重新索引。问题似乎就在这里,索引该列是唯一合理的答案。 因为每次重新索引大约需要 10 分钟!并且每天大约有 10.000 个新行......所以每天重新索引会很好(例如在凌晨 3 点)......但我不想在重新索引时锁定表 10 分钟。 【参考方案1】:

你需要一个索引,就这么简单。

另外,您提到 varchar 但您的列不是可变长度的,因此 char(32) 会更合适。

如果您担心在插入新行时维护索引的成本,您可以考虑将表分区为更小的块。例如,基于散列的第一个字符,您可以有 16 个单独的表,例如table_0, table_1....table_f - 现在每个表只包含 30,000 条记录。或者您可以对前 2 个字符进行分区以提供 256 个表。

虽然您可以手动执行此操作,但请查看 mysql's built in support for partitioning too。

【讨论】:

嗨 Paul ... char(32) 是一个不错的提示...另一方面,当我达到百万条记录时,表分区将再次无用...我更关心的是“当索引按时间变“旧”时重新索引” ... 索引不会变老,你只是从重建它获得一些性能优势。请注意,在 InnoDB 上使用 OPTIMIZE TABLE 可能不是最快的方法 - 删除并重新创建索引可能更有效 - 请参阅mysqlperformanceblog.com/2010/12/09/… 请注意,分区仍然可以帮助您,因为您只会锁定 1/16(或1/256th) 的行数。 Paul,没关系……但无论如何我都不想锁定表。我不能允许。我会做一些测试。谢谢 InnoDB 表在索引创建期间只有一个写锁,所以你只能被锁住,不能进行插入。如果这些哈希是随机分配的,您可以避免为重新创建索引的分区创建新哈希。 ...当然,另一种选择是在您可以安排一些停机时间之前不费心重新创建索引。您可能会发现这在性能方面是完全可以接受的。

以上是关于优化 MySQL 中的 hash 搜索的主要内容,如果未能解决你的问题,请参考以下文章

一致性 hash 和 Solr 千万级数据分布式搜索引擎中的应用

JAVA面试题之三—Mysql索引了解嘛?怎么优化查询效率?

优化 MySQL 全文搜索查询?

Mysql查询优化——范围搜索

MySQL ISAM 搜索优化

优化位置搜索mysql脚本