【发布时间】:2012-08-04 01:49:02
【问题描述】:
我有一个要存储文件路径的表 - 所以我有一个 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 可能是有意义的,因为它应该使用字符串更好。)
【问题讨论】:
-
不确定“部分索引”是什么意思。该术语通常涉及不涵盖表的所有行的索引(这是 MySQL 不支持的) - 它通常不用于描述仅索引部分列值的索引。
-
他的意思是前缀索引,它是一个涵盖CHAR/VARCHAR/*TEXT/*BLOB列的前N个字符的索引。例如,创建索引 my_index(some_field(50)) 来索引 some_field 的前 50 个字符。
标签: mysql sql performance indexing varchar