我对MySQL索引的工作原理非常感兴趣,更具体地说,它们如何在不扫描整个表的情况下返回所请求的数据?
我知道这离题了,但如果有人能给我详细解释一下,我会非常非常感谢。
我对MySQL索引的工作原理非常感兴趣,更具体地说,它们如何在不扫描整个表的情况下返回所请求的数据?
我知道这离题了,但如果有人能给我详细解释一下,我会非常非常感谢。
当前回答
您必须知道的第一件事是,索引是一种避免扫描整个表以获得您正在寻找的结果的方法。
有不同种类的索引,它们是在存储层实现的,所以它们之间没有标准,它们也取决于你使用的存储引擎。
InnoDB和B+树索引
对于InnoDB,最常见的索引类型是基于B+树的索引,它以排序的顺序存储元素。此外,您不必访问实际表来获取索引值,这使得您的查询返回速度更快。
关于这种索引类型的“问题”是,您必须查询最左边的值才能使用索引。因此,如果您的索引有两个列,例如last_name和first_name,那么查询这些字段的顺序非常重要。
给定下面的表格:
CREATE TABLE person (
last_name VARCHAR(50) NOT NULL,
first_name VARCHAR(50) NOT NULL,
INDEX (last_name, first_name)
);
这个查询将利用索引:
SELECT last_name, first_name FROM person
WHERE last_name = "John" AND first_name LIKE "J%"
但接下来的一个则不然
SELECT last_name, first_name FROM person WHERE first_name = "Constantine"
因为首先查询的是first_name列而不是索引中最左边的列。
最后一个例子更糟糕:
SELECT last_name, first_name FROM person WHERE first_name LIKE "%Constantine"
因为现在,你比较的是索引中最右边字段的最右边部分。
哈希索引
这是一种不同的索引类型,不幸的是,只有内存后端支持。它速度极快,但仅对完全查找有用,这意味着您不能将其用于>、<或like等操作。
因为它只适用于内存后端,所以您可能不会经常使用它。我现在能想到的主要情况是,您在内存中创建一个临时表,其中包含来自另一个选择的一组结果,并使用散列索引在这个临时表中执行许多其他选择。
如果您有一个大的VARCHAR字段,您可以在使用B-Tree时“模拟”使用哈希索引,方法是创建另一列并在其中保存大值的哈希。假设您要在字段中存储一个url,值相当大。您还可以创建一个名为url_hash的整数字段,并在插入url时使用像CRC32这样的哈希函数或任何其他哈希函数来哈希。然后,当你需要查询这个值时,你可以这样做:
SELECT url FROM url_table WHERE url_hash=CRC32("http://gnu.org");
上述示例的问题在于,由于CRC32函数生成了一个非常小的散列,因此最终会在散列值中产生大量冲突。如果你需要精确的值,你可以通过以下方法修复这个问题:
SELECT url FROM url_table
WHERE url_hash=CRC32("http://gnu.org") AND url="http://gnu.org";
即使碰撞数很高,哈希仍然是值得的,因为你只会对重复的哈希执行第二次比较(字符串一)。
不幸的是,使用这种技术,您仍然需要点击表来比较url字段。
总结
每当你想谈论优化时,你可能会考虑一些事实:
整数比较比字符串比较快得多。以InnoDB中哈希索引仿真为例进行了说明。 也许,在流程中添加额外的步骤会使其更快,而不是更慢。可以通过以下事实来说明这一点:优化SELECT可以分为两个步骤,第一个步骤将值存储在新创建的内存表中,然后在第二个表上执行较重的查询。
MySQL也有其他索引,但我认为B+树索引是最常用的,哈希索引是一个很好的东西,但你可以在MySQL文档中找到其他索引。
我强烈推荐你去读“高性能MySQL”这本书,上面的答案肯定是基于它关于索引的章节。
其他回答
看看这个链接:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
它们是如何工作的,这是一个太宽泛的主题,无法在一篇SO帖子中涵盖。
下面是我所见过的关于索引的最好的解释之一。不幸的是,它是SQL Server而不是MySQL。我不确定这两者有多相似……
基本上,索引是所有按顺序排序的键的映射。有了一个按顺序排列的列表,它就不需要检查每个键,而是可以这样做:
1:去列表的中间-比我想要的高还是低?
2:如果高,就去中间和底部的中间点,如果低,就去中间和顶部的中间点
3:是高还是低?再次跳转到中间点,等等。
使用该逻辑,您可以在大约7步的时间内在排序列表中找到一个元素,而不是检查每一项。
显然,这里有很多复杂的东西,但这给了你基本的概念。
我想发表我的意见。我还远不是数据库专家,但我最近读了一些关于这个主题的文章;足以让我试着申请ELI5。所以,这是一个外行的解释。
我的理解是,索引就像你的表的迷你镜子,很像一个关联数组。如果你给它一个匹配的键,那么你可以在一个“命令”中跳转到那一行。
但是如果没有索引/数组,查询解释器必须使用for循环遍历所有行并检查是否匹配(全表扫描)。
拥有索引的“缺点”是额外的存储空间(用于迷你镜像),而“优点”是更快地查找内容。
请注意(依赖于您的db引擎)创建主键、外键或唯一键会自动设置各自的索引。同样的原理基本上就是这些钥匙为什么以及如何工作。
基本上表上的索引就像书中的索引一样(这就是这个名字的由来):
Let's say you have a book about databases and you want to find some information about, say, storage. Without an index (assuming no other aid, such as a table of contents) you'd have to go through the pages one by one, until you found the topic (that's a full table scan). On the other hand, an index has a list of keywords, so you'd consult the index and see that storage is mentioned on pages 113-120,231 and 354. Then you could flip to those pages directly, without searching (that's a search with an index, somewhat faster).
当然,索引的有用程度取决于许多事情——举几个例子,使用上面的明喻:
if you had a book on databases and indexed the word "database", you'd see that it's mentioned on pages 1-59,61-290, and 292 to 400. In such case, the index is not much help and it might be faster to go through the pages one by one (in a database, this is "poor selectivity"). For a 10-page book, it makes no sense to make an index, as you may end up with a 10-page book prefixed by a 5-page index, which is just silly - just scan the 10 pages and be done with it. The index also needs to be useful - there's generally no point to index e.g. the frequency of the letter "L" per page.
Let's suppose you have a book, probably a novel, a thick one with lots of things to read, hence lots of words. Now, hypothetically, you brought two dictionaries, consisting of only words that are only used, at least one time in the novel. All words in that two dictionaries are stored in typical alphabetical order. In hypothetical dictionary A, words are printed only once while in hypothetical dictionary B words are printed as many numbers of times it is printed in the novel. Remember, words are sorted alphabetically in both the dictionaries. Now you got stuck at some point while reading a novel and need to find the meaning of that word from anyone of those hypothetical dictionaries. What you will do? Surely you will jump to that word in a few steps to find its meaning, rather look for the meaning of each of the words in the novel, from starting, until you reach that bugging word.
这就是SQL中索引的工作方式。假设字典A是PRIMARY INDEX,字典B是KEY/SECONDARY INDEX,并将获取单词含义的愿望作为QUERY/SELECT语句。 索引将有助于以非常快的速度获取数据。如果没有索引,您将不得不从头开始查找数据,这是一项不必要的耗时且昂贵的任务。
有关索引和类型的更多信息,请看这个。