我对MySQL索引如何工作非常感兴趣,更具体地说,他们如何在不扫描整个表的情况下返回所请求的数据?
这是偏离主题的,我知道,但如果有人可以向我详细解释这一点,我会非常,非常感谢。
答案 0 :(得分:477)
基本上,表上的索引就像书中的索引(名称来自的位置):
假设你有一本关于数据库的书,你想找一些关于存储的信息。没有索引(假设没有其他帮助,例如目录),您必须逐个浏览页面,直到找到主题(那是full table scan
)。
另一方面,索引有一个关键字列表,所以你可以参考索引,看看在第113-120,231和354页上提到了storage
。然后你可以直接翻到这些页面而不搜索(这是一个索引搜索,有点快。)
当然,索引的用处取决于很多东西 - 一些例子,使用上面的明喻:
答案 1 :(得分:238)
您必须知道的第一件事是索引是一种避免扫描整个表格以获得您正在寻找的结果的方法。
存在不同类型的索引,它们在存储层中实现,因此它们之间没有标准,它们也依赖于您正在使用的存储引擎。
对于InnoDB,最常见的索引类型是基于B + Tree的索引,它以排序顺序存储元素。此外,您不必访问实际表来获取索引值,这使您的查询返回更快。
关于此索引类型的“问题”是您必须查询最左边的值才能使用索引。因此,如果您的索引有两列,例如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
等操作。
由于它仅适用于内存后端,因此您可能不会经常使用它。我现在能想到的主要情况是你在内存中用一组来自另一个select的结果创建一个临时表,并使用哈希索引在这个临时表中执行许多其他选择。
如果你有一个很大的VARCHAR
字段,你可以在使用B-Tree时“模拟”哈希索引的使用,方法是创建另一个列并在其上保存一个大值的哈希值。假设你在一个字段中存储一个url,值非常大。您还可以创建一个名为url_hash
的整数字段,并使用哈希函数(如CRC32
或任何其他哈希函数)在插入URL时对其进行哈希处理。然后,当您需要查询此值时,您可以执行以下操作:
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";
即使碰撞数量很高,仍然值得散列,因为你只会对重复的哈希值执行第二次比较(字符串1)。
不幸的是,使用这种技术,你仍然需要点击表格来比较url
字段。
每次您想谈论优化时可能会考虑的一些事实:
整数比较比字符串比较快。可以通过InnoDB
中关于哈希索引仿真的示例来说明。
也许,在一个过程中添加额外的步骤会使它更快,而不是更慢。可以通过以下事实来说明:SELECT
可以通过将其分成两个步骤来优化{{1}},使第一个存储值存储在新创建的内存表中,然后在第二个表上执行较重的查询。
MySQL也有其他索引,但我认为B + Tree是最常用的,哈希值是一件好事,但您可以在MySQL documentation中找到其他索引。
我强烈建议您阅读“高性能MySQL”一书,上面的答案肯定是基于其关于索引的章节。
答案 2 :(得分:34)
索引基本上是按顺序排序的所有键的映射。按顺序列表,然后它可以执行以下操作,而不是检查每个键:
1:进入列表中间 - 是高还是低于我正在寻找的?
2:如果更高,则进入中间和底部之间的中间位置,如果是低位,中位和顶部
3:更高还是更低?再次跳到中间点等。
使用该逻辑,您可以在大约7个步骤中找到排序列表中的元素,而不是检查每个项目。
显然存在复杂性,但这给了你基本的想法。
答案 3 :(得分:4)
请看一下这个链接:http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
他们的工作方式过于宽泛,无法涵盖一篇SO帖子。
Here是我见过的索引的最佳解释之一。不幸的是它适用于SQL Server而不是MySQL。我不确定两者有多相似......
答案 4 :(得分:3)
参加this视频,了解有关建立索引的更多详情
简单索引 您可以在表上创建唯一索引。唯一索引意味着两行不能具有相同的索引值。以下是在表上创建索引的语法
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)
答案 5 :(得分:0)
我想加2美分。我还远不是数据库专家,但是最近我已经阅读了一些有关该主题的文章。足以让我尝试提供ELI5。所以,这是外行的解释。
我这样理解,索引就像表的微型镜像,非常像关联数组。如果用匹配的键输入它,那么您可以在一个“命令”中跳到该行。
但是,如果您没有该索引/数组,则查询解释器必须使用for循环遍历所有行并检查是否匹配(全表扫描)。
拥有索引具有额外存储空间(对于该微型镜像而言)的“缺点”,以换取更快地查找内容的“好处”。
请注意(取决于您的数据库引擎),创建主键,外键或唯一键也会自动设置相应的索引。相同的原则基本上就是这些键的工作原理和原因。
答案 6 :(得分:0)
MySQL使用了额外的间接层:辅助索引记录指向主索引记录,并且主索引本身保存磁盘上的行位置。如果行偏移量发生变化,则只需更新主索引。
注意:磁盘数据结构在图中看起来很平坦,但实际上是一个 B +树。
来源:link
答案 7 :(得分:0)
在MySQL InnoDB中,有两种类型的索引。
主键,称为聚簇索引。索引关键字与 B + Tree叶子节点中的实际记录数据。
非聚集索引的辅助密钥。这些索引仅将主键的关键字以及它们自己的索引关键字存储在B + Tree叶子节点中。因此,当从二级索引进行搜索时,它将首先找到其主关键字索引关键字,然后扫描主关键字B + Tree来查找真实的数据记录。与主索引搜索相比,这将使二级索引变慢。但是,如果select
列都在辅助索引中,则无需再次查找主索引B + Tree。这称为覆盖索引。
答案 8 :(得分:0)
让我们假设您有一本书,可能是一本小说,是一本厚实的书,里面有很多东西可以阅读,因此单词很多。 假设,现在,您带来了两个词典,该词典仅在小说中至少使用过一次,仅由仅使用的单词组成。 两个词典中的所有单词均以典型的字母顺序存储。在假设词典A 中,单词仅打印一次 ,而在假设词典B 中,单词印刷次数多在小说中。请记住,两个词典中的单词都按字母顺序排序。 现在,您在阅读小说时陷入了困境,并且需要从这些假想词典中的任何一个中找到该单词的含义。你会做什么?当然,您将通过几个步骤跳到该单词以查找其含义,而不是从头开始查找小说中每个单词的含义,直到找到那个臭虫。
这是索引在SQL中的工作方式。将字典A当作主索引,将字典B当作键/次要索引,并且您希望将单词的含义作为查询/选择语句。 该索引将有助于以非常快的速度获取数据。没有索引,您将不得不从开始的,不必要的耗时的高成本任务中寻找数据。
有关索引和类型的更多信息,请look this。