zoukankan      html  css  js  c++  java
  • 高性能的索引策略

    索引是最佳的解决方案吗

    索引并不总是最好用的工具

    只有在帮助存储引擎快速查找到记录的好处大于带来的额外工作时,索引才是有效的

    ① 对于小表,大部分时间全表扫描更高效

    ② 对于中到大型表,索引是有效的

    ③ 对于特大型表,建立和使用索引的代价随之增长,最好使用分区技术(直接区分查询需要的一组数据,而非一条一条记录匹配)

    不同数据结构的索引

    一. B-Tree 索引(对索引列顺序存储,适合查找范围数据)

    关于 B-Tree 索引的知识回顾 :若某表有一个多列索引 idx(a,b,c) ,那么如下的 Where 条件是否可以走索引,如何走索引?

    select * from instance where a=xx and b>xx and c=xx;

    答案 :可以走索引,a 和 b 字段可以走索引,c 无法走索引

    该 SQL 语句的 Where 条件已经符合最左前缀匹配原则,此处不叙述相关内容

    如果查询有某个列的范围查询,那么此列右面(当前例子中即 b 右面)的字段查询无法走索引

    二. Hash 索引(哈希索引,Memory 存储引擎支持)

    基于哈希表实现,对所有索引列计算得出一个哈希码(hash code)

    MySQL 中只有 Memory 存储引擎支持哈希索引,也是 Memory 存储引擎的默认索引类型

    三. R-Tree 索引(空间数据索引,MyISAM 存储引擎支持)

    四. FullText 索引(全文索引)

    全文索引是一种特殊的索引,查找的是文本中的关键词,而不是比较索引中的值(更类似于搜索引擎,而不是 Where 匹配)

    全文索引注意更多的细节,停用词、词干、复数、布尔搜索等

    在相同的列上创建 B-Tree 索引和 FullText 索引不会有冲突,全文索引适用于 Match Against 匹配,而非 Where 匹配

    B-Tree 索引的优点

    减少服务器需要扫描的行的数量(通过索引获得回表查询的指针,或实现索引覆盖)

    帮助服务器避免排序和临时表(B-Tree 索引按顺序存储,可以 Oder By 和 Group By 操作)

    可以将随机 IO 变成顺序 IO(B-Tree 索引按顺序存储,可以 Oder By 和 Group By 操作)

    哈希索引(Memory)

    哈希索引基于哈希表实现,MySQL 中只有 Memory 存储引擎支持哈希索引

    哈希索引不是按照索引值顺序存储的,无法按照字段的顺序进行排序

    哈希索引只支持等值比较查询,包括 = 、IN() 、<=> (注意和 <> 不同,<=> 个人理解可以类比做 IS),不支持任何范围查询

    哈希索引维护麻烦,如果在某个选择性很低(哈希冲突很高)的字段上建立哈希索引,当在表中删除一行记录时,存储引擎要遍历哈希索引中哈希值链表的每一行,找到并删除对应的行的引用,冲突越多,代价越大

    自适应哈希索引(InnoDB)

    InnoDB 存储引擎有一个特性,叫自适应哈希索引

    某些索引值被使用的非常频繁时,会在内存中基于 B-Tree 索引之上,再建立一个哈希索引

    这让 B-Tree 索引也具有了哈希索引的一些优点,比如快速的哈希查找

    这是一个完全自动、内部的行为,用户无法控制或者配置,但可以关闭该功能

    索引优化案例 - 长字段索引如何查的更快?

    案例 :某表存储了大量长字段的 URL,业务需要根据 URL 进行查找,URL 上建立了索引

    # 存储大量的 URL, 而且需要根据 URL 进行搜索和查找
    mysql> select id from url where url="http://www.mysql.com";
    # 使用 B-Tree 存储 URL ,存储的内容很大,因为 URL 很长,查询速度就很慢
    

    解决方案 :删除原 URL 上建立的索引,新增 一个被索引的 url_crc 列,使用 CRC32 哈希

    mysql> select id from url where url="http://www.mysql.com"
        -> and url_crc=CRC32("http://www.mysql.com"); 
    # 这样做性能非常高,MySQL 优化器会使用这个选择性很高、体积很小的基于 url_crc 列的索引完成查找
    # CRC32 获取的是 32 位整数,当数据量大于 93000 之后,有 1% 的概率产生哈希冲突
    # 为避免哈希冲突,将字段值和对应 CRC32() 哈希值一起写到 Where 条件中即可
    

    该情况下是伪哈希索引,索引的结构其实还是 B-Tree ,这个 B-Tree 的叶子节点只包含哈希值行指针,而不存储字段值,不能避免读取行,但内存中读取行较快,对性能的影响不明显

    哈希索引维护,需要创建一个触发器

    delimiter $$
    -- 插入时对 url_crc 字段进行赋值
    create trigger pseudohash_crc_ins 
    before insert on pseduhash
    for each row begin
    set NEW.url_crc=crc32(NEW.url);
    end$$
    -- 更新时对 url_crc 字段进行更新
    create trigger pseudohash_crc_upd 
    before update on pseduhash
    for each row begin
    set NEW.url_crc=crc32(NEW.url);
    end$$
    delimiter ;
    

    关于多列索引和多个单列索引

    首先,多个单列索引是不推荐的

    如下示例中,如果是两个索引,将对两个单列索引进行扫描,将结果进行合并

    算法无非有三种 : OR 条件的联合(union)、AND 条件的相交(intersection)、以及前两者的情况都包括的联合和相交

    # 有两个单列索引 film_id 和 actor_id
    mysql> select film_id,actor_id from ethan.film_actor
        -> where film_id = 1 and actor = 1; 
    # 这种情况下,就应该创建一个多列索引了
    # OR 条件的联合需要花费大量的 CPU、内存 在算法的缓存、排序和合并操作上
    # 多个单列索引的查询成本(消耗CPU和内存资源),甚至不如全表扫描
    

    多列索引选择合适的索引顺序

    选择性较高的,需要放在多列索引的前面

    mysql> select count(*),sum(age=25),sum(region="河北省") from itzone_m1;
    +----------+-------------+-------------------------+
    | count(*) | sum(age=25) | sum(region="河北省")    |
    +----------+-------------+-------------------------+
    |    10000 |         56  |                     297 |
    +----------+-------------+-------------------------+
    1 row in set (0.01 sec)
    
    # 类似这种,如果想要建立 age、region 字段的联合索引,就应该把 age 放在前面,重复值较少,选择性较高
    # 多列索引的第一列,若接近于总行数 count(*) ,也代表着这个索引没什么用
    

    InnoDB 与 MyISAM 数据分布

    禁止使用 UUID 作为主键

    要避免随机的(不连续、值的范围分布很大)聚集索引

    使用 UUID 作为聚集索引的主键,使用 UUID 作为聚集索引,数据的插入时随机的,使数据没有任何的聚集特性

    记录成长过程
  • 相关阅读:
    浅谈 iOS 事件的传递和响应过程
    iOS 之渐变颜色
    系统enum的一些样式
    Storyboard操作的2个小技巧
    iOS 动画初步
    iOS之Runtime初应用
    Block使有注意点
    使用ios系统自带分享
    IOS原生地图与高德地图
    反向传值实例
  • 原文地址:https://www.cnblogs.com/zzzwqh/p/14804697.html
Copyright © 2011-2022 走看看