我有一个要存储文件路径的表 - 所以我有一个 varchar 字段,大小为 4096(linux 中的默认 MAX_PATH 大小)。但是,我需要能够对某个目录中的所有文件路径进行查询,所以我正在考虑进行如下查询:
SELECT *
FROM files_table
WHERE files_table.path LIKE "/my/awesome/dir/%"
当我在我的数据库上使用路径字段 UNINDEXED 运行它时,大约需要 10 秒。好的,考虑到我的表大小约为 400 万,并且它是一个未索引的字段,我可以看到它需要一段时间。但是,当我索引它时,索引大小为 500,查询时间会跳跃......最多大约 30 秒!
这对我来说似乎很困惑。有人对可能导致这种情况的原因有任何想法吗?
对于那些渴望更多数据的人:
作为一些额外的数据 - 我尝试在查询上运行“解释”,发现它确实是使用我的索引,但它报告 key_len 仅为 5!这似乎也很奇怪。
另外 - 虽然我想听到我的问题的一个好的答案(因为我想了解这里发生了什么!),但我也愿意接受这样的想法,“我不知道它为什么这样做,但它没有重要,因为你真的应该像这样设计你的数据库......”排序。对于那些倾向于这种方式的人,我真正想做的是构建一个数据库结构来查询来自大型网络文件系统的各种(缓存)数据。我知道仅存储文件路径可能是解决此问题的最天真的方法,但我想我会尝试将其作为首次通过的实现,然后看看它把我带到了哪里。
编辑:
所以,更多的挖掘/信息:实际索引是一个多列索引 - 第一个索引是一个 int,保存一个 batch_id(即,表保存有关文件系统的缓存信息,所以每个快照都有自己的 batch_id),第二个是我对路径 varchar 的部分索引。因此,当 EXPLAIN 说索引 key_len 时,前 4 个字节实际上是用于 batch_id - 这意味着它只有一个字节的路径索引!
哦,“实际”查询也确实限制了 batch_id,所以它看起来更像这样:
SELECT *
FROM files_table
WHERE batch_id=5
AND files_table.path LIKE "_globalSoft/my/awesome/dir/%"
其次 - 我的数据库中很大一部分文件的路径以“_”开头 - 上面查询中的“_globalSoft”就是一个例子。(是的,路径都是相对的。)因此,如果 key_len 仅为 5,则键中唯一使用的字符可能是前导“_” - 这可以解释为什么它这么慢。
当然,这仍然引出了为什么它只使用前导“_”的问题。在阅读 MySQL 索引的文档(http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html)时,我注意到了这一行:
字符串会自动进行前缀和结束空间压缩。请参见第 13.1.8 节,“CREATE INDEX 语法”。
不幸的是,给定的链接没有说明字符串前缀压缩,我很难找到有关它的大量信息。我找到的信息都是关于 MyISAM 的,我现在正在使用 InnoDB。(虽然切换到 MyISAM 可能是有意义的,因为它应该使用字符串更好。)