innodb 索引问题

284 阅读4分钟
  1. extra 值的区别:

一共有以下值

  • Using index
  • using whre using index
  • null
  • using where
  • using index condition
  • using file sort

现在来一一验证以下值的区别以及产生这些值的条件

创建表

create table test_order
(
    id int auto_increment primary key,
    user_id int,
    order_id int,
    order_status tinyint,
    create_date datetime
);

create table test_orderdetail
(
    id int auto_increment primary key,
    order_id int,
    product_name varchar(100),
    cnt int,
    create_date datetime
);

create index idx_userid_order_id_createdate on test_order(user_id,order_id,create_date);

create index idx_orderid_productname on test_orderdetail(order_id,product_name);

然后执行存储过程 分别生成2张表各 50w条记录

CREATE PROCEDURE `test_insertdata`(IN `loopcount` INT)
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
    declare v_uuid  varchar(50);
    while loopcount>0 do
        set v_uuid = uuid();
        insert into test_order (user_id,order_id,order_status,create_date) values (rand()*1000,id,rand()*10,DATE_ADD(NOW(), INTERVAL - RAND()*20000 HOUR));
        insert into test_orderdetail(order_id,product_name,cnt,create_date) values (rand()*100000,v_uuid,rand()*10,DATE_ADD(NOW(), INTERVAL - RAND()*20000 HOUR));
        set loopcount = loopcount -1;
    end while;
END

执行函数 使用

call test_insertdata(500000);
//或者mysql 客户端点击 运行函数 输入50w 即可

Using index

  • 说明:查询的列被索引覆盖,并且where条件 是 ==索引的是前导列==, 则 extra 为 Using index
explain select user_id,order_id,create_date from test_order
where user_id = 1;

所以触发Using index 必须满足2个条件

==1. 查询列被索引覆盖,==

==2. where条件 是 索引前导列(最左原则)==

Using where; Using index

  • 查询的列被索引覆盖,但不是前导列,则extra 为Using where; Using index
explain select user_id,order_id,create_date from test_order where order_id = 1;
  • 查询的列被索引覆盖,但是where 筛选条件是前导列的一个范围,同样意味着无法直接通过索引查找查询结果到符合的数据
explain select user_id,order_id,create_date from test_order where order_id >1 and order_id < 5;

Null

  • 使用主键索引,则key 为primary, extra 为null
explain select user_id from test_order where id =1;
  • 查询的列未被索引覆盖,但是where条件筛选是索引前导列,意味着用到了索引,但是部分字段未被索引覆盖,则需要通过回表的方式来实现
explain select user_id,order_id,order_status,create_date from test_order where user_id =1;

Using where

  • 查询的列未被覆盖,where条件不是索引的前导列
explain select user_id,order_id,order_status,create_date from test_order where order_id =1;
  • 查询的列未被覆盖,where条件不是索引
explain select user_id,order_id,order_status,create_date from test_order where order_status =1;

using where 说明是通过索引或者表扫描的方式进行where 条件的过滤。反过来说,没有可用的索引查找,所以也需要考虑索引加回表 与 全表扫描之间的代价,如果type 为all 则是全表扫描的意思

Using index condition

  1. 查询的不全是 索引,搜索条件是前导列的 (范围 <> 或者 like %)
explain select user_id,order_id,order_status,create_date from test_order where user_id >1 and user_id < 5;

索引2大类 聚集索引以及 普通索引

  1. 聚集索引通常是 主键索引
B+数结构如图


    1-9
    <>
  1-5 7-9
  <>   <>
 1  5   7   9
 
 1  5   7   9
 A  D   G   J
 B  E   H   K
 C  F   I   L
 

如上所示 聚集索引最终指向的是行记录数据

我们来看一下 普通索引

B+数结构如图

     a - z
      <>
    A-F   G-L
    
    A  F  G  L
    1  5  7  9

如上所示 是指向该记录的索引 所以如果想要查询这个记录 我们需要==回表==的方式进行再一次查询聚集索引

mysql 事务的实现

A atomicity 原子性 概述:将一个事务视为最小单位 要么全部成功,要么整体失败 实现:当事务发生异常的时候,就需要回滚操作,而使用 undo log 来记录 之前操作的语句 -- 如果一旦发生异常,将会执行undo log 里面的语句, 这里要注意的是 undo log 记录的是 反向操作语句 比如insert 对应的是 delete

事务的状态 begin commit failed C Consistency 一致性 一致性的2个理解

  1. 同一个sql,相同的数据库实例,则改变的行记录是一致的
  2. 银行存取钱操作, 这个就需要代码中实现 实现

I Isolation 隔离性 概念:在mysql 并行执行事务的时候,保证能够有序的进行事务执行,则事务需要具备隔离性 实现 锁 悲观锁,乐观锁 杭锁 表锁 行锁 共享锁 互斥锁 4中隔离级别以及衍生处的 幻读,不可重复读 脏读

D Durability 持久性 概念:当一个事务提交后,还没来的急写进磁盘就宕机,则再下一次数据库重启时能够恢复数据,这就是持久性 实现:通过 redo log 重做日志来实现

mysql 执行事务的过程,将行记录从磁盘写到内存中,更新内存中的数据,生成一条重做日志 将修改后的数据写入 redo buffer ,当事务执行时,进而将其写入重做日志中,并将缓存中的数据更新到磁盘中。因为重做日志是512字节 与磁盘扇区大小相同,就可以保证原子性,不会因为断电而写入一半的这种情况。所以当重启后,mysql会从重做日志中重新执行mysql命令,这就是持久性