MySQL索引如何工作?

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

我知道这是无关紧要的,但是如果有人能够详细解释这一点,我会非常非常感激。


基本上,表格上的索引就像书中的索引(这就是名字的来源):

假设你有一本关于数据库的书,并且你想找到一些关于存储的信息。 如果没有索引(假设没有其他帮助,例如目录),您必须逐页浏览这些页面,直到找到主题(这是full table scan )。 另一方面,一个索引有一个关键字列表,所以你可以查阅索引并查看第113-120,231和354页上提到的storage 。然后你可以直接翻到那些页面,而不用搜索(这是一个搜索一个索引,有点更快)。

当然,索引的有用性取决于很多东西 - 一些例子,使用上面的比喻:

  • 如果您有一本关于数据库的书籍并将“数据库”这个词编入索引,您会发现第1-59,61-290页和第292页至第400页提到了它。在这种情况下,索引没有太大的帮助,它可能浏览页面的速度会更快(在数据库中,这是“差的选择性”)。
  • 对于一本10页的书来说,做一个索引是没有意义的,因为你最终可能会得到一本10页的书,前面有一个5页索引,这很愚蠢 - 只需扫描10页并完成它。
  • 索引也需要有用 - 通常没有意义,例如每页的字母“L”的频率。

  • 你必须知道的第一件事是索引是一种避免扫描整个表来获得你要找的结果的方法。

    有不同种类的索引,它们在存储层中实现,因此它们之间没有标准,它们也依赖于您正在使用的存储引擎。

    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

    由于它只适用于内存后端,因此您可能不会经常使用它。 我现在能想到的主要情况是,你在内存中创建一个临时表,并使用另一个select的一组结果,并使用散列索引在此临时表中执行很多其他选择。

    如果你有一个大的VARCHAR字段,你可以在使用B-Tree时“模拟”使用散列索引,方法是创建另一列并保存大值的哈希值。 假设你在一个字段中存储一个url,并且这些值非常大。 您也可以创建一个名为url_hash的整数字段,并在插入时使用散列函数(如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分解为两个步骤来优化SELECT ,使第一个将值存储在新创建的内存表中,然后在第二个表上执行较重的查询。

  • MySQL也有其他的索引,但我认为B + Tree是有史以来使用最多的,哈希是一个很好的事情,但你可以在MySQL文档中找到其他索引。

    我强烈建议你阅读“高性能MySQL”一书,上面的答案绝对是基于它关于索引的章节。


    基本上,索引是按顺序排序的所有键的映射。 按照顺序排列列表,而不是检查每个键,它可以做这样的事情:

    1:转到列表的中间 - 比我要找的更高还是更低?

    2:如果较高,则进入中间和底部之间的中间点,如果较低,中间和顶部

    3:更高还是更低? 再次跳到中间点等。

    使用该逻辑,您可以按大约7个步骤在排序列表中查找元素,而不是检查每个项目。

    显然有复杂性,但是这给了你基本的想法。

    链接地址: http://www.djcxy.com/p/39375.html

    上一篇: How do MySQL indexes work?

    下一篇: How to shrink/purge ibdata1 file in MySQL