### 8.3.1 MySQL 如何使用索引

[](<>)

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

大多数 MySQL 索引 (`首要的关键`,`独特`,`指数`， 和`全文`) 存储在[B树](glossary.html#glos_b_tree).例外：空间数据类型的索引使用 R-trees；`记忆`表也​​支持[哈希索引](glossary.html#glos_hash_index);`InnoDB`使用倒排列表`全文`索引。

一般来说，索引的使用如以下讨论中所述。特定于哈希索引的特征（如在`记忆`表）在[第 8.3.9 节，“B 树和哈希索引的比较”](index-btree-hash.html).

MySQL 对这些操作使用索引：

-   查找与 a 匹配的行`在哪里`条款很快。

-   从考虑中消除行。如果在多个索引之间进行选择，MySQL 通常使用找到最少行数的索引（最多[可选择的](glossary.html#glos_selectivity)指数）。

-   [](<>) [](<>)如果表有一个多列索引，优化器可以使用索引的任何最左边的前缀来查找行。例如，如果您有一个三列索引`(col1, col2, col3)`，您已在`(col1)`,`(col1, col2)`， 和`(col1, col2, col3)`.有关详细信息，请参阅[第 8.3.6 节，“多列索引”](multiple-column-indexes.html).

-   在执行连接时从其他表中检索行。如果将列声明为相同的类型和大小，MySQL 可以更有效地使用列上的索引。在这种情况下，[`VARCHAR`](char.html)和[`字符`](char.html)如果它们被声明为相同的大小，则被认为是相同的。例如，`VARCHAR(10)`和`字符(10)`大小相同，但`VARCHAR(10)`和`字符(15)`不是。

    对于非二进制字符串列之间的比较，两列应使用相同的字符集。例如，比较一个`utf8`列`拉丁语1`列排除使用索引。

    如果值不能在没有转换的情况下直接比较，则比较不同的列（例如，将字符串列与时间或数字列进行比较）可能会阻止使用索引。对于给定的值，例如`1`在数字列中，它可能比较等于字符串列中的任意数量的值，例如`'1'`,`“1”`,`'00001'`， 要么`'01.e1'`.这排除了对字符串列使用任何索引。

-   要找到[`最小（）`](aggregate-functions.html#function_min)要么[`最大限度（）`](aggregate-functions.html#function_max)特定索引列的值*`key_col`*.这是由检查您是否正在使用的预处理器优化的`在哪里 *`key_part_N`* = *`持续的`*`在之前发生的所有关键部分上*`key_col`*在索引中。在这种情况下，MySQL 为每个[`最小（）`](aggregate-functions.html#function_min)要么[`最大限度（）`](aggregate-functions.html#function_max)表达式并将其替换为常量。如果所有表达式都替换为常量，则查询立即返回。例如：

    ```
    SELECT MIN(key_part2),MAX(key_part2)
      FROM tbl_name WHERE key_part1=10;
    ```

-   如果排序或分组是在可用索引的最左前缀上完成的，则对表进行排序或分组（例如，`订购人 *`key_part1`*, *`key_part2`*`）。如果所有关键部分都跟在`DESC`，以相反的顺序读取密钥。（或者，如果索引是降序索引，则按正序读取键。）请参阅[第 8.2.1.16 节，“按优化排序”](order-by-optimization.html),[第 8.2.1.17 节，“按优化分组”](group-by-optimization.html)， 和[第 8.3.13 节，“降序索引”](descending-indexes.html).

-   在某些情况下，可以优化查询以在不查阅数据行的情况下检索值。（为查询提供所有必要结果的索引称为[覆盖指数](glossary.html#glos_covering_index).) 如果查询仅使用表中包含在某个索引中的列，则可以从索引树中检索所选值以获得更快的速度：

    ```
    SELECT key_part3 FROM tbl_name
      WHERE key_part1=1
    ```

    对于小表或报表查询处理大部分或所有行的大表的查询，索引不太重要。当查询需要访问大部分行时，顺序读取比通过索引更快。即使查询不需要所有行，顺序读取也可以最大限度地减少磁盘寻道。看[第 8.2.1.23 节，“避免全表扫描”](table-scan-avoidance.html)详情。
