数据库索引设计与优化

栏目: 数据库 · 发布时间: 5年前

内容简介:这是读完了 <高性能MySQL> , <数据库索引设计与优化> 和 MySQL Manual 之后的总结。本文的所有知识都是与MySQL相关的,其他 数据库也许有不同。诸如AND, OR等语句,MySQL可能会使用多个索引检索出结果,然后对多个结果进行AND,OR等操作。符合三星的查询是最佳的查询,但是实际过程我们往往难以做到,例如如果使用了ORM,一般都没有可能拿到第三颗星。

这是读完了 <高性能MySQL> , <数据库索引设计与优化> 和 MySQL Manual 之后的总结。本文的所有知识都是与 MySQL 相关的,其他 数据库也许有不同。

  • 索引的本质是用写入时间换取查询时间

  • 所有的优化都是有有效上限的,例如内存当然是越大越好,但是当你把所有的数据和缓存等都装下了之后,内存再往上增加就不会再 有明显的所用。CPU当然是越快越好,但是如果你的查询不是CPU bound,那么也不会有明显作用。磁盘随机IO当然是越快越好,也许有一天 磁盘可以达到和内存相当的速度,那时候磁盘也许就不再是瓶颈。

  • 通常情况下来说,MySQL只能使用一颗索引树,但是5.0之后有索引合并的优化,这种情况下可以使用多个索引,例如:

mysql jiajun@127.0.0.1:fd_test> EXPLAIN SELECT * FROM user WHERE mobile='12345678910' OR fullname='小白';
+------+---------------+---------+-------------+---------------------+---------------------+-----------+--------+--------+-----------------------------------------------+
| id   | select_type   | table   | type        | possible_keys       | key                 | key_len   | ref    | rows   | Extra                                         |
|------+---------------+---------+-------------+---------------------+---------------------+-----------+--------+--------+-----------------------------------------------|
| 1    | SIMPLE        | user    | index_merge | MOBILE_IDX,IDX_NAME | MOBILE_IDX,IDX_NAME | 767,768   | <null> | 2      | Using union(MOBILE_IDX,IDX_NAME); Using where |
+------+---------------+---------+-------------+---------------------+---------------------+-----------+--------+--------+-----------------------------------------------+
1 row in set
Time: 0.010s

诸如AND, OR等语句,MySQL可能会使用多个索引检索出结果,然后对多个结果进行AND,OR等操作。

  • 三星索引

    • 第一颗星在 WHERE 语句的所有条件。如果该条件可以使用一个索引(假设有多个condition,则应当有一个联合索引),这样可以 加快过滤的速度
    • 第二颗星在 ORDER BY 语句。详见文章最下面的引用。使用例如 SELECT * FROM user ORDER BY mobile LIMIT 5 这样的查询 时,MySQL可以直接从 mobile 的索引进行查找,充分的利用了 mobile 索引的有序性。
    • 第三颗星在 SELECT 后面的字段,如果 SELECT 所取出来的字段都是索引里的值,那么就无需从真正的数据里获取到指定的 那一行来获取所需要的数据了。

符合三星的查询是最佳的查询,但是实际过程我们往往难以做到,例如如果使用了ORM,一般都没有可能拿到第三颗星。

  • 我们来假装自己是MySQL服务器,模拟一下查询的过程。首先收到请求校验请求等这些过程我们就先忽略,直接看到利用索引的 这个过程。

    • 优化器决定是否使用某个索引
    • 使用某个索引之后,索引通常是B树或者其变种。通常根节点一定在内存中,其下层的节点可能会在内存中也可能会在磁盘上,取决 于操作系统内存是否充足以及是否将其缓存。
      • 假设将其缓存在内存中,则一步一步往下查找,在内存中自然速度是非常快的,一直到找到叶子节点
      • 假设没有缓存在内存中,则找到子节点所在的磁盘中的块,读取数据,然后继续进行,一直找到叶子节点
      • 此前的步骤中,数据往往是连续的。找到叶子节点之后,读取叶子节点中的数据,找到数据真正所在的行,这一步往往是 随机I/O。因为数据所存储的地方可能是不同的。
        • 但是主键通常会是一张表中有且仅有的聚族索引。聚族索引是连续存储的索引。
  • 联合索引是个好东西,但是使用联合索引查询时,会遵循最左匹配原则,例如有个联合索引是 (key1, key2, key3) ,那么能用上 的查找是 (key1)(key1, key2)(key1, key2, key3) 。其实这里我有一点不明白,其实索引可以特殊处理一下,然后可以跳 过其中某个值进行使用,例如 (key1, key3) ,原因是无论是 int还是varchar都可以换算成大小固定的值,例如int是4 byte, varchar换成一个指针,这样就可以进行固定大小的偏移从而跨值利用索引。也许是为了降低复杂度所以目前并没有这样做,也许是有 其他原因。

另外为什么是最左匹配原则呢?因为比较索引的时候是从左往右比较。

  • JOIN 是怎么使用索引的?最朴素的JOIN自然是 for...for 嵌套,例如 SELECT A.* FROM A JOIN B ON A.key1 = B.key1 ,可能会 生成类似于
def query():
    result = []

    for row_in_b in B:
        for row_in_a in A:
            if row_in_b.key1 == row_in_a.key1:
                result.append(row_in_a)

    return result

这样的代码,如果在连表的字段上有索引,那么可能会生成:

def query():
    result = []

    for row_in_b in B:
        if row_in_b.key1 in A.key1:
            row_in_a = [i for i in A where A.key1 = row_in_b.key1]
            result.extend(row_in_a)

    return result

从而把时间复杂度从 O(n^2) 降低到 O(n lgn)

  • IN 语句是怎么使用索引的?MySQL会把 IN 后面的条件先排序,然后进行范围查找。因为B树是有序的,所以可以减少很多无关数据。

还有很多。。。不过不想写了。。。还是看书吧,哈哈哈


以上所述就是小编给大家介绍的《数据库索引设计与优化》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

免费

免费

克里斯•安德森 / 蒋旭峰、冯斌、璩静 / 中信出版社 / 2012-10 / 68.00元

一种商业模式既可以统摄未来的市场,也可以挤垮当前的市场——在我们这个现代经济社会里,这并不是一件不可能的事情。 “免费”就是这样的一种商业模式,它所代表的正是数字化网络时代的商业未来。 在《免费》这本书中,克里斯•安德森认为,新型的“免费”并不是一种左口袋出、右口袋进的营销伎俩,而是一种把货物和服务的成本压低到零的新型卓越能力。在20世纪“免费”是一种强有力的推销手段,而在21世纪它已经成为......一起来看看 《免费》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具