• 数据库索引


    索引

    索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息,就像一本书的目录一样,可以加快查询速度。

    实现

    1. B 树
      B 树是自平衡树数据结构。其保持数据排序,并允许在对数时间内完成搜索、顺序存取、插入和删除。

      B 树是二叉搜索树的泛化,其结点可以具有多于两个的子结点。

    2. B+ 树
      相比于 B 树:

      • B+ 树的非叶子结点只用来保存索引,不存储数据,所有的数据都保存在叶子结点;而B树的非叶子结点也会保存数据。
        这样就使得B+ 树的 查询效率更加稳定,均为从根结点到叶子结点的路径。

      • B+ 树的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对 B 树更小,同样空间可以读入更多的结点,所以 B+ 树的 磁盘读写代价更低

      相比于红黑树:

      • 更少的查找次数
        红黑树的出度为 2,而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。

      • 利用磁盘预读特性
        为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的磁盘旋转时间,速度会非常快。
        操作系统一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。
        数据库系统将索引的一个结点的大小设置为页的大小,使得一次 I/O 就能完全载入一个结点。并且可以利用预读特性,相邻的结点也能够被预先载入。

    3. Hash 索引

      • 哈希索引能以 O(1) 时间进行查找,但是失去了有序性,无法用于排序与分组

      • 只支持精确查找,无法用于部分查找和范围查找。

    聚簇索引

    聚簇索引树 的叶子结点中存的是整行 数据,表中行的物理顺序与索引顺序相同。

    一个表只能包含一个聚簇索引。因为物理顺序是 唯一 的。

    在 InnoDB 中,默认使用主键作为聚簇索引,即主键索引。

    相对应,非聚簇索引树 的叶子结点不存储数据:

    • 在 InnoDB 中,非聚簇索引树的叶子结点存储 主键值,再由主键二次索引得到数据,因此也称为二级索引。
    • 在 MyISAM 中,主键索引和辅助索引树叶子结点存储的都是行数据的 地址,都是非聚簇索引。

    聚簇索引的优势

    1. 使用聚簇索引检索时,数据和索引在同一位置,速度很快。

    2. 使用非聚簇索引检索,虽然需要二级检索,但是维护的成本下降了。因为辅助索引叶结点存的是主键,当表数据位置发生变化时,辅助索引树并不需要改动。

    3. 适合用在排序的场合,相关的数据顺序排列在一起,可以一并取出,不需要多次 I/O。

    索引优化

    1. 独立的列
      在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。

    2. 多列索引
      在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。

    3. 索引列的顺序
      让选择性强(区分度高)的索引列放在前面。

    4. 覆盖索引
      索引包含所有需要查询的字段的值。

    • 对于 MyISAM,在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用。
    • 对于 InnoDB,若辅助索引能够覆盖查询,则无需访问主键索引,即不需要 回表

    性能优化

    使用 EXPLAIN 分析

    explain select ... ;
    

    输出:

    • id:选择标识符
    • select_type:查询的类型
    • table:表
    • partitions:匹配的分区
    • type:表的连接类型
    • possible_keys:查询时可能使用的索引
    • key:实际使用的索引
    • key_len:索引字段的长度
    • ref:列与索引的比较
    • rows:扫描出的行数
    • filtered:按表条件过滤的行百分比
    • extra:执行情况的描述和说明

    优化数据访问

    1. 减少请求的数据量

      • 只返回必要的列:最好不要使用 SELECT * 语句。

      • 只返回必要的行:使用 LIMIT 语句来限制返回的数据。

      • 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。

    2. 减少服务器端扫描的行数

      • 最有效的方式是使用索引来覆盖查询。

    重构查询方式

    1. 切分大查询
      一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。

    2. 分解大连接查询
      将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有:

      • 缓存更高效
        对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。
        分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。

      • 减少锁竞争

      • 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩

      • 查询本身效率也可能会有所提升




    参考资料:CyC2018/CS-Notes

  • 相关阅读:
    背水一战 Windows 10 (90)
    背水一战 Windows 10 (89)
    背水一战 Windows 10 (88)
    背水一战 Windows 10 (87)
    背水一战 Windows 10 (86)
    背水一战 Windows 10 (85)
    背水一战 Windows 10 (84)
    背水一战 Windows 10 (83)
    背水一战 Windows 10 (82)
    背水一战 Windows 10 (81)
  • 原文地址:https://www.cnblogs.com/JL916/p/12693575.html
Copyright © 2020-2023  润新知