Mysql大法--索引

索引是什么
数据库中专门用于帮助用户快速查找数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置吗,然后直接获取。
索引有什么用
约束和加速查找
索引有哪些

  • 普通索引
  • 唯一索引
  • 主键索引
  • 联合索引(多列)
    • 联合主键索引
    • 联合唯一索引
    • 联合普通索引

– MySQL测试任务:使用存储过程,往表中插入千万级数据,根据索引优化速度
– 1.使用索引查询
– 2.不使用索引查
– 3.比较两者查询速度的差异

一、创建数据和索引

1、创建索引测试表

DROP TABLE IF EXISTS big_data;
CREATE TABLE big_data(
id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(16) DEFAULT NULL,
age int(11),
email varchar(64) default null
)ENGINE=MYISAM DEFAULT CHARSET=utf8;

注意:MYISAM存储引擎不产生引擎事务,数据插入速度极快,为方便快速插入千万条测试数据,等我们插完数据,再把存储类型修改为InnoDB
2、创建存储过程,插入数据

CREATE PROCEDURE `insert_data_p`(IN num INT)
BEGIN
DECLARE n INT DEFAULT 1;
WHILE n <= num DO
INSERT INTO big_data(name,age,email)values(concat('xiaokeai',n),rand()*50,concat('xiaokeai',n,'@jc.com'));
set n=n+1;
end while;
ENd;

3、调用存储过程,插入一百万条数据

CALL insert_data_p(10000000);

4、修改引擎(此步骤可以忽略)

ALTER TABLE `big_data` ENGINE=INNODB;

5、通过主键索引查询

select * from big_data where id = 89000

注意: 大家可能会发现一个问题: 第一次查询时,会有点慢,而第二次查询时就要比第一次快很多, why?
原因: 表引擎使用innodb.第一次查询会走数据文件,第二次直接走buffer_pool(缓冲池),所以比直接查询数据文件要快
*
6、为name字段创建普通索引

CREATE INDEX index_name ON big_data (name);

二、组合索引的生效原则

原则: 从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用;

三、正确使用索引

数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
  使用索引,我们必须知道:
    (1)创建索引
    (2)命中索引
    (3)正确使用索引

  • 数据准备
#1. 准备表
create table userinfo(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);

#2. 创建存储过程,实现批量插入记录
delimiter $$ #声明存储过程的结束符号为$$
create procedure auto_insert1()
BEGIN
    declare i int default 1;
    while(i<3000000)do
        insert into userinfo values(i,concat('alex',i),'male',concat('egon',i,'@oldboy'));
        set i=i+1;
    end while;
END$$ #$$结束
delimiter ; #重新声明分号为结束符号

#3. 查看存储过程
show create procedure auto_insert1\G 

#4. 调用存储过程
call auto_insert1();

准备300w条数据
  • 测试
- like '%xx'
            select * from userinfo where name like '%al';
        - 使用函数
            select * from userinfo where reverse(name) = 'alex333';
        - or
            select * from userinfo where id = 1 or email = 'alex122@oldbody';
            特别的:当or条件中有未建立索引的列才失效,以下会走索引
                    select * from userinfo where id = 1 or name = 'alex1222';
                    select * from userinfo where id = 1 or email = 'alex122@oldbody' and name = 'alex112'
        - 类型不一致
            如果列是字符串类型,传入条件是必须用引号引起来,不然...
            select * from userinfo where name = 999;
        - !=
            select count(*) from userinfo where name != 'alex'
            特别的:如果是主键,则还是会走索引
                select count(*) from userinfo where id != 123
        - >
            select * from userinfo where name > 'alex'
            特别的:如果是主键或索引是整数类型,则还是会走索引
                select * from userinfo where id > 123
                select * from userinfo where num > 123
        - order by
            select email from userinfo order by name desc;
            当根据索引排序时候,选择的映射如果不是索引,则不走索引
            特别的:如果对主键排序,则还是走索引:
                select * from userinfo order by nid desc;
         
        - 组合索引最左前缀
            如果组合索引为:(name,email)
            name and email       -- 使用索引
            name                 -- 使用索引
            email                -- 不使用索引

四、注意事项

1.避免使用select *
2.count(1)或count(列) 代替 count(*)
3. 创建表时尽量时 char 代替 varchar
4. 表的字段顺序固定长度的字段优先
5. 组合索引代替多个单列索引(经常使用多个条件查询时)
6. 使用连接(JOIN)来代替子查询(Sub-Queries)
7. 不要有超过5个以上的表连接(JOIN)
8. 优先执行那些能够大量减少结果的连接。
9. 连表时注意条件类型需一致
10.索引散列值不适合建索引,例:性别不适合

五、时间(执行计划)

explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

explain select * from big_data where age = "47" and name ="xiaokeai6996"

在这里插入图片描述参数说明
select_type:
查询类型
SIMPLE 简单查询
PRIMARY 最外层查询
SUBQUERY 映射为子查询
DERIVED 子查询
UNION 联合
UNION RESULT 使用联合的结果
table:
正在访问的表名
type:
查询时的访问方式,性能:all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
ALL 全表扫描,对于数据表从头到尾找一遍
select * from userinfo;
特别的:如果有limit限制,则找到之后就不在继续向下扫描
select * from userinfo where email = ‘alex112@oldboy’
select * from userinfo where email = ‘alex112@oldboy’ limit 1;
虽然上述两个语句都会进行全表扫描,第二句使用了limit,则找到一个后就不再继续扫描。

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

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

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

REF: 根据索引查找一个或多个值
select * from userinfo where name = ‘alex112’;

EQ_REF: 连接时使用primary key 或 unique类型
select userinfo2.id,userinfo.name from userinfo2 left join tuserinfo on userinfo2.id = userinfo.id;

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

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

possible_keys:可能使用的索引

key:真实使用的

key_len:  MySQL中使用索引字节长度

rows: mysql估计为了找到所需的行而要读取的行数 ------ 只是预估值

extra:
该列包含MySQL解决查询的详细信息
“Using index”
此值表示mysql将使用覆盖索引,以避免访问表。不要把覆盖索引和index访问类型弄混了。
“Using where”
这意味着mysql服务器将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引。
“Using temporary”
这意味着mysql在对查询结果排序时会使用一个临时表。
“Using filesort”
这意味着mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成。
“Range checked for each record(index map: N)”
这个意味着没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的

五、慢日志查询

  1. 查看慢日志信息(配置信息)
show variables like "%query%";

在这里插入图片描述参数注释:
slow_query_log 慢查询开启状态 OFF 未开启 ON 为开启
slow_query_log_file 慢查询日志存放的位置(这个目录需要MySQL的运行帐号的可写权限,一般设置为MySQL的数据存放目录)

  1. 开启慢日志(修改配置信息)
    在这里插入图片描述
  2. 再次查看慢日志信息

show variables like '%log_queries_not_using_indexes';在这里插入图片描述
4. 开启索引状态
set global log_queries_not_using_indexes = on;在这里插入图片描述

六、大数据量分页优化

优化前:

select * from big_data limit 30000,10;

运行结果:
在这里插入图片描述在这里插入图片描述
简单粗暴,就是不允许查看这么靠后的数据,比如百度就是这样的
在这里插入图片描述
解决方案:(1)在查询下一页时把上一页的行id作为参数传递给客户端程序,然后sql就改成了

select * from big_data where id>30000 limit 10;

运行结果:
在这里插入图片描述在这里插入图片描述
这条语句执行也是在毫秒级完成的,id>3w其实就是让mysql直接跳到这里了,不用依次在扫描全面所有的行。
如果你的table的主键id是自增的,并且中间没有删除和断点,那么还有一种方式,比如100页的10条数据

select * from big_data where id>100*10 limit 10;

在这里插入图片描述
如果你的table的主键id是自增的,并且中间没有删除和断点,那么还有一种方式,比如100页的10条数据

select * from big_data where id>100*10 limit 10;

本期学习到此结束,欢迎大家关注指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值