Python全栈之路-MySQL(六)

1 索引:

1.1 索引类型

  • 普通索引 特性:加速查找
  • 主键索引 特性:加速查找 + 不能为空 + 不能重复
  • 唯一索引 特性:加速查找 + 不能重复
  • 联合索引 特性:加速查找
    • 联合普通索引
    • 联合主键索引
    • 联合唯一索引
  • 全文索引:会借助第三方工具做

索引存储种类(某种格式存储):

  • hash索引:存储的顺序和数据表不一致,找单值速度快
  • btree索引(mysql常用索引):一般用于数据库的索引综合效率较高

1.2 索引操作

创建普通索引:

create index index_email on user(email);

删除普通索引:

drop index index_email on user;

创建唯一索引:

create unique index index_name on user(name);

删除唯一索引:

drop index index_name on user;

创建联合索引:

create index index_email_name on user(email,name);

注:联合索引遵循最左前缀匹配原则

select * from user where email='abc123431@qq.com'; -- 走索引
select * from user where email='abc123431@qq.com' and name='alex3423'; -- 走索引
select * from user where name='alex3423' and email='abc123431@qq.com'; -- 不走索引
select * from user where name='alex3423'; -- 不走索引
注意:联合索引效率 > 索引合并

删除联合索引:

drop index index_email_name on user;

有索引和无索引的区别:

无索引:从前到后依次查找
有索引:创建额外文件(某种格式存储),会占用磁盘空间

1.3 索引补充

建立索引:

  • 额外的文件保存特殊的数据结构
  • 查询快,插入更新删除慢
  • 命中索引

索引名词补充

  • 覆盖索引 在索引文件中直接获取数据
    select * from user where email='alex3423@qq.com';
  • 索引合并 把多个单列索引合并使用
    select * from user where email='abc123431@qq.com' and id =123432;

1.4 命中索引

只有满足下面两点索引才能加速查询(假设nid和email是索引列)
- 创建索引
- 命中索引

以下几种情况不能命中索引:

  • like '%xx'
    select * from tb1 where name like '%cn';

  • 使用函数
    select * from tb1 where reverse(name) = 'wupeiqi';

  • or
    select * from tb1 where nid = 1 or name = 'seven@live.com';
    特别的:当or条件中有未建立索引的列才失效,以下会走索引
    select * from tb1 where nid = 1 or email = 'seven';
    select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'

  • 类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where email = 999;

  • !=
    select * from tb1 where email != 'abc123431@qq.com'
    特别的:如果是主键,则还是会走索引
    select * from tb1 where nid != 123

  • select * from tb1 where name > 'alex'
    特别的:如果是主键或索引是整数类型,则还是会走索引
    select * from tb1 where nid > 123
    select * from tb1 where num > 123

  • order by
    注:部分版本会存在此问题
    select name from tb1 order by email desc; -- 根据哪一列order by就取select哪一列的值
    当根据索引排序时候,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
    select * from tb1 order by nid desc;

  • 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email -- 使用索引
    name -- 使用索引
    email -- 不使用索引

其他注意事项:

  • 避免使用select *
  • count(1)或count(列) 代替 count(*)
  • 创建表时尽量时 char 代替 varchar
  • 表的字段顺序固定长度的字段优先
  • 组合索引代替多个单列索引(经常使用多个条件查询时)
  • 尽量使用短索引,比如如果字段类型是text类型,则不能再该列建立索引
  • 使用连接(JOIN)来代替子查询(Sub-Queries)
  • 连表时注意条件类型需一致
  • 索引散列值(重复少)不适合建索引,例:性别不适合

1.5 执行计划

查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const (一般情况下是准确的)

ALL             全表扫描,对于数据表从头到尾找一遍
                select * from tb1;
                特别的:如果有limit限制,则找到之后就不在继续向下扫描
                        select * from tb1 where email = 'seven@live.com'
                        select * from tb1 where email = 'seven@live.com' limit 1;
                        虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。

INDEX           全索引扫描,对索引从头到尾找一遍
                select nid from tb1;

RANGE          对索引列进行范围查找
                select *  from tb1 where name < 'alex';
                PS:
                    between and
                    in
                    >   >=  <   <=  操作
                    注意:!= 和 > 符号


INDEX_MERGE     合并索引,使用多个单列索引搜索
                select *  from tb1 where name = 'alex' or nid in (11,22,33);

REF             根据索引查找一个或多个值
                select *  from tb1 where name = 'seven';

EQ_REF          连接时使用primary key 或 unique类型
                select tb2.nid,tb1.name from tb2 left join tb1 on tb2.nid = tb1.nid;



CONST           常量
                表最多有一个匹配行,因为仅有一行,在这行的列值可被优化器剩余部分认为是常数,const表很快,因为它们只读取一次。
                select nid from tb1 where nid = 2 ;

SYSTEM          系统
                表仅有一行(=系统表)。这是const联接类型的一个特例。
                select * from (select nid from tb1 where nid = 1) as A;


possible_keys  可能使用的索引

1.6 慢查询日志配置

  • 执行时间大于1s(自定义)的
  • 执行语句未走索引的

global变量在线配置,立即生效

修改配置文件重启MySQL生效

1.7 分页实战

select * from user limit 200000,10;

当起始位置越大时,查询效率越低

实战:提高博客中的页码翻页查询效率
解决方案:

    - 不让看
    - 索引表中扫(效率提升不是很大)
        select * from user where id in (select id from user limit 200000,10);

    - 记录当前页的起始id和结束id
        max_id 当前页最大id
        min_id 当前页最小id
        每页显示10条数据
        情况1:页面只有上一页下一页
        select * from user where id > max_id limit 10;
        select * from user where id < max_id order by id desc limit 10;
        情况2:用户进行翻页时可跳转几页
        例如,用户跳转了3页向后翻页
        select * from user where id 
        in (select id from user where id > max_id limit 30) as N order by N.id desc limit 10 order by N.id asc;
        例如,用户跳转了3页向前翻页
        select * from user where id 
        in (select id from user where id < min_id order by id desc limit 30) as N order by N.id desc limit 10 order by N.id asc;

    
    ps:id不连续,所以无法直接使用id范围进行查找
原文地址:https://www.cnblogs.com/wanyuetian/p/7008376.html