我对MySQL索引的工作原理非常感兴趣,更具体地说,它们如何在不扫描整个表的情况下返回所请求的数据?

我知道这离题了,但如果有人能给我详细解释一下,我会非常非常感谢。


当前回答

看这个视频了解更多关于索引的细节

简单的索引 您可以在表上创建唯一的索引。唯一索引意味着两行不能有相同的索引值。下面是在表上创建Index的语法

CREATE UNIQUE INDEX index_name
ON table_name ( column1, column2,...);

您可以使用一个或多个列来创建索引。例如,我们可以使用tutorial_author在tutorials_tbl上创建索引。

CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author)

您可以在表上创建一个简单的索引。只需从查询中省略UNIQUE关键字以创建简单的索引。简单索引允许表中有重复的值。

如果要按降序索引列中的值,可以在列名后添加保留字DESC。

mysql> CREATE UNIQUE INDEX AUTHOR_INDEX
ON tutorials_tbl (tutorial_author DESC)

其他回答

基本上表上的索引就像书中的索引一样(这就是这个名字的由来):

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.

我想发表我的意见。我还远不是数据库专家,但我最近读了一些关于这个主题的文章;足以让我试着申请ELI5。所以,这是一个外行的解释。


我的理解是,索引就像你的表的迷你镜子,很像一个关联数组。如果你给它一个匹配的键,那么你可以在一个“命令”中跳转到那一行。

但是如果没有索引/数组,查询解释器必须使用for循环遍历所有行并检查是否匹配(全表扫描)。

拥有索引的“缺点”是额外的存储空间(用于迷你镜像),而“优点”是更快地查找内容。

请注意(依赖于您的db引擎)创建主键、外键或唯一键会自动设置各自的索引。同样的原理基本上就是这些钥匙为什么以及如何工作。

您必须知道的第一件事是,索引是一种避免扫描整个表以获得您正在寻找的结果的方法。

有不同种类的索引,它们是在存储层实现的,所以它们之间没有标准,它们也取决于你使用的存储引擎。

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”这本书,上面的答案肯定是基于它关于索引的章节。

在MySQL InnoDB中,有两种索引类型。

Primary key which is called clustered index. Index key words are stored with real record data in the B+Tree leaf node. Secondary key which is non clustered index. These index only store primary key's key words along with their own index key words in the B+Tree leaf node. So when searching from secondary index, it will first find its primary key index key words and scan the primary key B+Tree to find the real data records. This will make secondary index slower compared to primary index search. However, if the select columns are all in the secondary index, then no need to look up primary index B+Tree again. This is called covering index.

索引用于快速查找具有特定列值的行。如果没有索引,MySQL必须从第一行开始,然后通读整个表以找到相关的行。桌子越大,花费就越多。如果表中存在相关列的索引,MySQL可以快速确定要在数据文件中间查找的位置,而不必查看所有数据。这比按顺序读取每一行快得多。

索引添加一个包含搜索条件列和指针的数据结构 对象所在行的内存磁盘地址 其他信息 对索引数据结构进行排序,优化查询效率 该查询查找索引中的特定行;索引指向将查找剩余信息的指针。 索引将查询必须搜索的行数从17减少到4。