MySQL Explain简介及简单SQL优化_explain using join buffer-程序员宅基地

技术标签: Mysql  MySQL  Explain  SQL优化  

索引优化
数据准备

create table course
(
cid int(3),
cname varchar(20),
tid int(3)
);
create table teacher
(
    tid int(3),
    tname varchar(20),
    tcid int(3)
);
create table teachercard
(
tcid int(3),
tcdesc varchar(200)
);
insert into course values(1,'java',1);
insert into course values(2,'html',1);
insert into course values(3,'sql',2);
insert into course values(4,'web',3);
insert into teacher values(1,'tz',1);
insert into teacher values(2,'tw',2);
insert into teacher values(3,'tl',3);
insert into teachercard values(1,'tzdesc');
insert into teachercard values(2,'twdesc');
insert into teachercard values(3,'tidesc');

查询课程编号为2 或 教师证编号为3 的老师信息

mysql> explain select t.* from teacher t,course c,teachercard tc where t.tid=c.tid and t.tcid=tc.tcid and (c.cid=2 or tc.tcid=3);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL                                               |
|  1 | SIMPLE      | tc    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+


(1)id: id 值相同,从上往下顺序执行,id 值不同,从大到小执行,t3-tc3-c4
    给teacher增加3条数据:

insert into teacher values(4,'ta',4);
insert into teacher values(5,'tb',5);
insert into teacher values(6,'tc',6);

mysql> explain select t.* from teacher t,course c,teachercard tc where t.tid=c.tid and t.tcid=tc.tcid and (c.cid=2 or tc.tcid=3);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | tc    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL                                               |
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |    16.67 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+

执行顺序变成了tc3-t6-c4

为什么执行顺序会变?原理?
因为数据量越小的越先执行。
原理:假设 a,b,c 3各表,数据量分别为 2 ,3 ,4 ,则笛卡尔积为  2 * 3 = 6 * 4 = 24
           如果设置  a为4条,b 为3 条,c为2条,        则笛卡尔积为 4 * 3 = 12 * 2 = 24
           虽然结果都是24,但中间结果一个是6,一个是12,中间结果越小越好。
           所以数据小的表 优先查询

 id 值不同:id值越大越先执行
 
 查询教授SQL磕碜的老师描述(desc)

select tc.* from teachercard tc,teacher t,course c where tc.tcid=t.tcid and t.tid=c.tid and c.cname='sql';
 子查询方式
 mysql> explain select tc.tcdesc from teachercard tc where tc.tcid=(select t.tcid from teacher t where t.tid=(select c.tid from course c where c.cname='sql'));
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY     | tc    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where |
|  2 | SUBQUERY    | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |    16.67 | Using where |
|  3 | SUBQUERY    | c     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

(2)select_type:
             PRIMARY:
             SUBQUERY:
             SIMPLE:简单查询(不包含子查询和union)

mysql> explain select * from course;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | course | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL  |
+----+-------------+--------+------------------+---------------+------+---------+------+------+----------+-------+

DERIVED:(使用到了临时表)如果在子查询中,table1 union table2,则table1 就是derived,table2为union

mysql> explain select cr.cname from ( select * from course where tid =1 union select * from course where tid=2 ) cr;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type  | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | PRIMARY      | <derived2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL            |
|  2 | DERIVED      | course     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where     |
|  3 | UNION        | course     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where     |
| NULL | UNION RESULT | <union2,3> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+


table中 derived2 表示 id=2 语句衍生出来的表
union2,3 表示id=2 和 id=3 的两张表进行union

union:看上例
union result: 看上例

(3) type:索引类型
    常见: system > const > eq_ref > ref > range > index > all  ,要对 type 进行优化,则前提是有索引
    其中: system,const 只是理想情况,实际能达到 ref > range

    system(忽略):只有一条数据的系统表;或 衍生表只有一条数据的主查询

    const:仅仅能查到一条数据的SQL,用于 primary key 或 unique 索引(与索引类型有关)
  

例:create table test01(tid int(3),tname varchar(20)); 
   insert into test01 values(1,'a');
   mysql> explain select * from (select * from test01) a  where tid=1;   ---tid为主键
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table  | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test01 | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+--------+------------+-------+---------------+---------+---------+-------+------+----------+-------+

    如果是普通索引
    

mysql> explain select * from (select * from test01) a  where tid=1;
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test01 | NULL       | ref  | idxtid        | idxtid | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+

    eq_ref:唯一索引,对于每个索引建的查询,返回匹配唯一行数据(有且只有1个,不能多,不能0),常见于索引列为主键或唯一索引。
    例:

mysql> explain select * from teacher t,teachercard tc where t.tcid=tc.tcid;   --t.tcid 唯一索引  tc.tcid 主键
+----+-------------+-------+------------+--------+---------------+------+---------+------------+------+----------+-------+
| id | select_type | table | partitions | type   | possible_keys | key  | key_len | ref        | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+------+---------+------------+------+----------+-------+
|  1 | SIMPLE      | tc    | NULL       | ALL    | PRIMARY       | NULL | NULL    | NULL       |    3 |   100.00 | NULL  |
|  1 | SIMPLE      | t     | NULL       | eq_ref | tcid          | tcid | 4       | ty.tc.tcid |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+--------+---------------+------+---------+------------+------+----------+-------+

 ref:非唯一索引,对于每个索引键的查询,返回匹配的所有行(0,多)

mysql> explain select * from teacher where tcid=1;      --tcid 辅助索引
+----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | teacher | NULL       | ref  | idxtcid       | idxtcid | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+

range:检索指定范围的行,where后面是一个范围查询(between,in, > ,>=, < ,<=, 其中 in 有可能失效)
        前提是where 的列必须有索引

index:查询全部索引中的数据,如果一个表中某一列a加了索引,则查的就是a这一列的所有数据,并不涉及到其他列
    

mysql> explain select tcid from teacher;  --tcid 为普通索引
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | teacher | NULL       | index | NULL          | idxtcid | 4       | NULL |    6 |   100.00 | Using index |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

    all:查询全部表中的数据

mysql> explain select tname from teacher;   --tname 无索引
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | teacher | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------+

(4)possible_keys:可能用到的索引,是一种预测,不准
(5)key:实际用到的索引
(6)key_len:索引的长度,作用:用于判断符合索引是否被完全使用。
    

例:create table test_k1 (name char(20) not null default '');
    alter table test_k1 add index index_name(name);
    mysql> explain select * from test_k1 where name='';
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | test_k1 | NULL       | ref  | index_name    | index_name | 80      | const |    1 |   100.00 | Using index |
+----+-------------+---------+------------+------+---------------+------------+---------+-------+------+----------+-------------+


    这里 key_len 显示为 80,而建表的时候是20,因为字符集的原因,utf8mb4 一个字符占4个字节,所以这里80 = 20 * 4,说明 name索引列被使用 

在新增1列,并加上普通索引
 

alter table test_k1 add column name1 char(20); 
alter table test_k1 add index index_name1(name1);
mysql> explain select * from test_k1 where name1='';
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key         | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_k1 | NULL       | ref  | index_name1   | index_name1 | 81      | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+

 为什么name1同样是20个字符,而key_len=81?
 因为name列定义的是不能为空,而name1可以为空,如果栏位定义为可以为空,则需要多占一个1字节用于标示可以为空,所以是81.
    

删掉索引
drop index index_name on test_k1;drop index index_name1 on test_k1;
创建复合索引
alter table test_k1 add index index_name_name1(name,name1);
mysql> explain select * from test_k1 where name1='';
+----+-------------+---------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key              | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | test_k1 | NULL       | index | NULL          | index_name_name1 | 161     | NULL |    1 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+


    为什么key_len=161?
    因为条件是name1='',而name和name1是复合索引,所以要用name1则必须要用name,所以 80 + 81 = 161
    在新增1列,并加上普通索引
    

alter table test_k1 add column name2 varchar(20); 
alter table test_k1 add index index_name2(name2);

mysql> explain select * from test_k1 where name2='';
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key         | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_k1 | NULL       | ref  | index_name2   | index_name2 | 83      | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+-------------+---------+-------+------+----------+-------+


    key_len 为什么等于 83?
    因为name2为可变长度,可变长度要用2个字节标示。 80 + 1(null) + 2(可变) = 83

    utf8:1个字符占3个字节
    utf8mb4:1个字符占4个字节
    gbk:1个字符占2个字节
    latin:1个字符占1个字节


(7)ref:指明当前表所参照的字段。
        select .... where a.c = b.x;  则 a 表应用了 b.x,如果 b.x 为常量,则ref的值为const。

mysql> explain select * from teacher t ,course c where t.tid=c.tid and t.tname='tw'; -- t.tid 主键,c.tid 普通索引,t.tname 普通索引
+----+-------------+-------+------------+------+-------------------+-----------+---------+----------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys     | key       | key_len | ref      | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+-----------+---------+----------+------+----------+-------+
|  1 | SIMPLE      | t     | NULL       | ref  | PRIMARY,idx_tname | idx_tname | 83      | const    |    1 |   100.00 | NULL  |
|  1 | SIMPLE      | c     | NULL       | ref  | idx_tid           | idx_tid   | 5       | ty.t.tid |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+-------------------+-----------+---------+----------+------+----------+-------+


    第一条,因为 t.tname ='tw' 为常量,所以这里ref 为 const
    第二条,因为 c 表引用了 ty.t.tid 作为条件,所以这里 ref 为 ty.t.tid


(8)rows:被索引优化查询的数据个数(索引优化后的结果有多少条数据)

(9)Extra:
    (i)using filesort: 性能消耗大;需要“额外”的一次排序(查询)。常见于 order by 语句中 
        

例:
create table test01(a1 char(3),a2 char(3),a3 char(3),index idx_a1(a1),index idx_a2(a2),index idx_a3(a3));
mysql> explain select * from test02 where a1='' order by a1;
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    | id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1        | idx_a1 | 13      | const |    1 |   100.00 | NULL  |
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+-------+


        为什么没有出现using filesort?
        因为 where 的条件跟 order by 的列是同一列。
        先根据 where 条件查出满足条件的数据,且a1是索引,查出来的数据本来就是排序好的,而order by 正好是按照a1排序,所以不会在需要 “额外”的一次排序(查询)


      

 mysql> explain select * from test02 where a1='' order by a2;
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+---------------------------------------+
    | id | select_type | table  | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra                                 |
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+---------------------------------------+
    |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1        | idx_a1 | 13      | const |    1 |   100.00 | Using index condition; Using filesort |
    +----+-------------+--------+------------+------+---------------+--------+---------+-------+------+----------+---------------------------------------+


        为什么出现using filesort?
        因为 where 的条件跟 order by 的列不是同一列。
        先根据 where 条件查出满足条件的数据,且a1是索引,查出来的数据是按照 a1 列排序的,而order by 的却是 a2,如果需要按照 a2 来排序,则需要多 “额外”的再按照 a2 排一次序(查询)

        符合索引:不能跨列(最佳左前缀)
        

mysql> explain select * from test02 where a1='' order by a3;
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+------------------------------------------+
    | id | select_type | table  | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra                                    |
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+------------------------------------------+
    |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1a2a3    | idx_a1a2a3 | 13      | const |    1 |   100.00 | Using where; Using index; Using filesort |
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+------------------------------------------+


        为什么会出现using filesort?
        因为建的是符合索引,a1 a3,中间少了a2.

        

mysql> explain select * from test02 where a1='' order by a2;
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+--------------------------+
    | id | select_type | table  | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra                    |
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+--------------------------+
    |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1a2a3    | idx_a1a2a3 | 13      | const |    1 |   100.00 | Using where; Using index |
    +----+-------------+--------+------------+------+---------------+------------+---------+-------+------+----------+--------------------------+


        这里是a1 和 a2,没有跨列

        小结:
        单索引情况下: where 哪些字段就 order by 哪些字段
        复合索引情况: where + order by 的栏位 按照复合索引的顺序使用,不要无序或跨列使用

    (ii) using temporary :性能损耗大,用到了临时表。常见于 group by 语句中
      

 例:mysql> explain select a1 from test02 where a1 in ('1','2') group by a2;
    +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------------------------------------------+
    | id | select_type | table  | partitions | type  | possible_keys | key        | key_len | ref  | rows | filtered | Extra                                                     |
    +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------------------------------------------+
    |  1 | SIMPLE      | test02 | NULL       | index | idx_a1a2a3    | idx_a1a2a3 | 39      | NULL |    1 |   100.00 | Using where; Using index; Using temporary; Using filesort |
    +----+-------------+--------+------------+-------+---------------+------------+---------+------+------+----------+-----------------------------------------------------------+


        避免:查询哪些列,就根据那些列group by


    (iii) using index:性能提升:索引覆盖(覆盖索引)。原因:不读取源文件,只从索引文件中获取数据(不需要回表查询)
                只要使用到的列,全部都在索引中,就是索引覆盖
            

mysql> explain select a1,a2 from test02 where a1='' and a2='';
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+
        | id | select_type | table  | partitions | type | possible_keys | key      | key_len | ref         | rows | filtered | Extra       |
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+
        |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1a2      | idx_a1a2 | 26      | const,const |    1 |   100.00 | Using index |
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------------+


        因为这里where 就是 a1 和 a2, 查的也是 a1 和 a2,故可以使用索引覆盖。


        

mysql> explain select a1,a3 from test02 where a1='' and a2='';
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------+
        | id | select_type | table  | partitions | type | possible_keys | key      | key_len | ref         | rows | filtered | Extra |
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------+
        |  1 | SIMPLE      | test02 | NULL       | ref  | idx_a1a2      | idx_a1a2 | 26      | const,const |    1 |   100.00 | NULL  |
        +----+-------------+--------+------------+------+---------------+----------+---------+-------------+------+----------+-------+


        因为这里where 就是 a1 和 a2, 但查的是 a1 和 a3,故不可以使用索引覆盖。

        如果用到了索引覆盖,会对 possible_keys 和 key 造成影响:
            a.如果没有where,则索引只出现在keys中;
            b.如果有where,则索引出现在key 和possible_keys中。


    (iv)using where(需要回表查询)
            假设age是索引列
            但查询语句 select age,name from ...where age=...此语句中必须会原表查name,因此会显示using where

    (iv)impossible where:where 字句永远为false

例: mysql> explain select a3 from test02 where a1='' and a1='1';
        +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
        | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra            |
        +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
        |  1 | SIMPLE      | NULL  | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL |     NULL | Impossible WHERE |
        +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
create table test03(
a1 int(4) not null,
a2 int(4) not null,
a3 int(4) not null,
a4 int(4) not null);
alter table test03 add index idx_a14(a1,a2,a3,a4);

mysql> explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a4=3 order by  a3;
+----+-------------+--------+------------+------+---------------+---------+---------+-------------+------+----------+--------------------------+
| id | select_type | table  | partitions | type | possible_keys | key     | key_len | ref         | rows | filtered | Extra                    |
+----+-------------+--------+------------+------+---------------+---------+---------+-------------+------+----------+--------------------------+
|  1 | SIMPLE      | test03 | NULL       | ref  | idx_a14       | idx_a14 | 8       | const,const |    1 |   100.00 | Using where; Using index |
+----+-------------+--------+------------+------+---------------+---------+---------+-------------+------+----------+--------------------------+

        以上SQL用到了a1,a2两个索引,该2个字段不需要回表查询,所以using index,而a4因为跨列了使用,造成该索引失效,需要回表查询,因此是using where,以上可以通过key_len看出。

mysql> explain select a1,a2,a3,a4 from test03 where a1=1  and a4=3 order by  a3;
+----+-------------+--------+------------+------+---------------+---------+---------+-------+------+----------+------------------------------------------+
| id | select_type | table  | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra                                    |
+----+-------------+--------+------------+------+---------------+---------+---------+-------+------+----------+------------------------------------------+
|  1 | SIMPLE      | test03 | NULL       | ref  | idx_a14       | idx_a14 | 4       | const |    1 |   100.00 | Using where; Using index; Using filesort |
+----+-------------+--------+------------+------+---------------+---------+---------+-------+------+----------+------------------------------------------+

    为什么这里出现了using filesort,而上面一句没出现?
    因为上句中 a1、a2 (a4失效,因为不连续)+ order by 的a3 ,是连续的,没有跨列。
    而下句中 a1、(a4失效,不连续) + order by 的 a3,中间少了a2,跨列了
    原理:因为a1,a2,a3,a4 是复合索引,所以上句中,根据 a1 和 a2 过滤出来的 a3,a4 的数据是排序好的,然后通过a4=3在过滤下,就ok了,不需要在额外排序了。
    而下句中,根据 a1 过滤出来的 a2 和 a3 是顺序的,但是排序的是按照 a3 ,中间少了a2,所以单独看a3不是顺序的,所以要额外进行一次排序

     总结:i.如果(a,b,c,d)符合索引和使用的顺序全部一致(且不跨列使用),则复合索引全部使用。如果部分一致(且不跨列使用),则使用部分索引。
         ii.where 和order 拼起来,不要跨列使用优化案例
    单表优化、2表优化、3表优化
    

(1)单表优化
create table book(
bid int(4) primary key,
name varchar(20) not null, 
authorid int(4) not null,
publicid int(4) not null,
typeid int(4) not null);
insert into book values(1,'tjava',1,1,2);
insert into book values(2,'tc',2,1,2);
insert into book values(3,'wx',3,2,1);
insert into book values(4,'math',4,2,3);

mysql> explain select bid from book where typeid in(2,3) and authorid=1 order by typeid desc;
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+
    |  1 | SIMPLE      | book  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where; Using filesort |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------------------+

    

优化:加索引
alter table book add index idx_bta(bid,typeid,authorid);   --因为顺序是bid,typeid,authorid

mysql> explain select bid from book where typeid in(2,3) and authorid=1 order by typeid desc;
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                                    |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
    |  1 | SIMPLE      | book  | NULL       | index | NULL          | idx_bta | 12      | NULL |    4 |    25.00 | Using where; Using index; Using filesort |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+


        这里 type 从 all 变成了 index,性能有所提升,但不理想,还有using filesort 和 using where 存在

        这里要提出的是上面建的符合索引不合理,因为根据sql语句的解析过程 :
        from .. on .. join .. where .. group by .. having .. select .. distinct .. order by .. limit
        可以看出 select 是在where后面的,所以复合索引的顺序应修改为 typeid,authorid,bid
        索引一旦进行升级优化,需要将之前废弃的索引删掉,防止干扰
        alter table book add index idx_tab(typeid,authorid,bid);
        可能有的会说有了typeid和authorid就行了,bid可以通过回表来查,但是,如果把bid也加进来的话可以使用using index,性能可以有一定的提升
        

mysql> explain select bid from book where typeid in(2,3) and authorid=1 order by typeid desc;
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
    |  1 | SIMPLE      | book  | NULL       | range | idx_tab       | idx_tab | 8       | NULL |    2 |   100.00 | Using where; Using index |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+

        这里将 using filesort 优化掉了

        因为 如果使用in的话,可能导致索引失效,所以将authorid 和 typeid 的位置互换(索引也换) 

mysql> explain select bid from book where authorid=1 and typeid in(2,3) order by typeid desc;
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
    | id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
    |  1 | SIMPLE      | book  | NULL       | range | idx_tab       | idx_tab | 8       | NULL |    2 |   100.00 | Using where; Using index |
    +----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+

         这里还是 using where;using index的原因?
        因为authorid=1 因为在索引列最左边,可以使用索引覆盖
        而typeid 因为使用的in,所以 typeid的索引失效,故需要回表,所以出现using where,从 key_len =8 就可以看出只使用到了1个列

        将typeid in(2,3) 换成 typeid=3进行验证:

mysql> explain select bid from book where  authorid=1 and typeid =3 order by typeid desc;
    +----+-------------+-------+------------+------+---------------+---------+---------+-------------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key     | key_len | ref         | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+---------+---------+-------------+------+----------+-------------+
    |  1 | SIMPLE      | book  | NULL       | ref  | idx_tab       | idx_tab | 8       | const,const |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+------+---------------+---------+---------+-------------+------+----------+-------------+

       这里using where 消失,


        总结:
            a.最佳左前缀,保持索引的定义和使用顺序要一致,不能跨列
            b.索引需要逐步优化
            c.将含 in 的范围查询,放到where 条件的最后,防止索引失效
    (2)2表优化
        例: 
        

create table teacher2(
tid int(4) primary key,
cid int (4) not null);

create table course2(cid int(4) ,cname varchar(20));
insert into teacher2 values(1,2);
insert into teacher2 values(2,1);
insert into teacher2 values(3,3);
insert into course2 values(1,'java');
insert into course2 values(2,'python');
insert into course2 values(3,'kotlin');

mysql> explain select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
    |  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where                                        |
    |  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |    33.33 | Using where; Using join buffer (Block Nested Loop) |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+


        索引往哪张表加?
        左外连接时(left outer join),给左边的表加索引,同理右外连接给右边的表加索引,总之就是在使用较频繁的字段上加索引,比如小表10条数据,大表100条数据,如果
        .. on 小表.c = 大表.c ,则小表的c字段每一条记录都要跟 大表.c 字段比对100次,故小表.c字段使用频繁,故在小表.c 字段上加索引

        结论:1.当编写 。。 on t.cid=c.cid 时,往往将数据量小的表放左边
              
        小表驱动大表

        增加索引
        

mysql> alter table teacher2 add index idx_cid(cid);
       alter table course2 add index idx_cname(cname);
mysql> explain select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';
        +----+-------------+-------+------------+------+---------------+---------+---------+----------+------+----------+-------------+
        | id | select_type | table | partitions | type | possible_keys | key     | key_len | ref      | rows | filtered | Extra       |
        +----+-------------+-------+------------+------+---------------+---------+---------+----------+------+----------+-------------+
        |  1 | SIMPLE      | c     | NULL       | ALL  | NULL          | NULL    | NULL    | NULL     |    3 |    33.33 | Using where |
        |  1 | SIMPLE      | t     | NULL       | ref  | idx_cid       | idx_cid | 4       | ty.c.cid |    1 |   100.00 | Using index |
        +----+-------------+-------+------------+------+---------------+---------+---------+----------+------+----------+-------------+

        
mysql> explain select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';
        +----+-------------+-------+------------+------+---------------+-----------+---------+----------+------+----------+-------------+
        | id | select_type | table | partitions | type | possible_keys | key       | key_len | ref      | rows | filtered | Extra       |
        +----+-------------+-------+------------+------+---------------+-----------+---------+----------+------+----------+-------------+
        |  1 | SIMPLE      | c     | NULL       | ref  | idx_cname     | idx_cname | 83      | const    |    1 |   100.00 | Using where |
        |  1 | SIMPLE      | t     | NULL       | ref  | idx_cid       | idx_cid   | 4       | ty.c.cid |    1 |   100.00 | Using index |
        +----+-------------+-------+------------+------+---------------+-----------+---------+----------+------+----------+-------------+

    (3)三张表优化
            a.小表驱动大表
            b.索引建立在经常查询的字段上

7.避免索引失效的一些原则 
    (1)复合索引
        a.复合索引,不要跨列或无需使用(最佳左前缀,如果最左边失效,则后面的全部失效)
        b.复合索引,尽量使用全索引匹配
    (2)不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
        不要:select ... where a.x * 3 =
    (3)复合索引不能使用不等于(!= 或 <> ) 或 is null (is not null,否则自身以及右侧全部失效
    (4)体验概率情况(<  >  =):原因是服务层中有SQL优化器,可能会影响我们的优化。
    

mysql> explain select * from book where authorid>1 and typeid=1;
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | book  | NULL       | ALL  | idxat         | NULL | NULL    | NULL |    4 |    25.00 | Using where |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+


        复合索引不能使用 >  ,否则自身及右边的索引失效        

mysql> explain select * from book where authorid<1 and typeid=2;
    +----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
    | id | select_type | table | partitions | type  | possible_keys | key   | key_len | ref  | rows | filtered | Extra                 |
    +----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+
    |  1 | SIMPLE      | book  | NULL       | range | idxat         | idxat | 4       | NULL |    1 |    25.00 | Using index condition |
    +----+-------------+-------+------------+-------+---------------+-------+---------+------+------+----------+-----------------------+


mysql> explain select * from book where authorid<4 and typeid=2;
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    | id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | book  | NULL       | ALL  | idxat         | NULL | NULL    | NULL |    4 |    25.00 | Using where |
    +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+


        上面2个sql完全一样,只是authorid 1 改成了4 ,但执行计划不一样,所以在有 > 、 < 、 = 的时候有概率跟你想的优化结果不一样

    索引优化,是一个大部分情况适用的结论,但由于SQL优化器等原因,该结论不是100%正确。
    一般而言,范围查询(< 、 > 、 in),之后的索引失效。

    (5)补救:尽量使用索引覆盖(using index)
    (6)like尽量以“常量”开头,不要以“%”开头,否则索引失效
    (7)不要类型转换(显示、隐士)
        

mysql> explain select * from teacher where tname='ab';
        +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
        | id | select_type | table   | partitions | type | possible_keys | key       | key_len | ref   | rows | filtered | Extra |
        +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
        |  1 | SIMPLE      | teacher | NULL       | ref  | idx_tname     | idx_tname | 83      | const |    1 |   100.00 | NULL  |
        +----+-------------+---------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
        
mysql> explain select * from teacher where tname=123;
        +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
        | id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
        +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+
        |  1 | SIMPLE      | teacher | NULL       | ALL  | idx_tname     | NULL | NULL    | NULL |    6 |    16.67 | Using where |
        +----+-------------+---------+------------+------+---------------+------+---------+------+------+----------+-------------+


        tname为varchar(20)
        下句中,tname=123,程序将数字123 转换成了字符串‘123’,及类型转换,造成索引失效
    (8)尽量不要使用or,否则索引失效
        

mysql> explain select * from teacher where tname='' and tcid >1;
        +----+-------------+---------+------------+------+-------------------+-----------+---------+-------+------+----------+-------------+
        | id | select_type | table   | partitions | type | possible_keys     | key       | key_len | ref   | rows | filtered | Extra       |
        +----+-------------+---------+------------+------+-------------------+-----------+---------+-------+------+----------+-------------+
        |  1 | SIMPLE      | teacher | NULL       | ref  | idxtcid,idx_tname | idx_tname | 83      | const |    1 |    83.33 | Using where |
        +----+-------------+---------+------------+------+-------------------+-----------+---------+-------+------+----------+-------------+
        

mysql> explain select * from teacher where tname='' or tcid >1;  --将or 左侧的tname索引也失效
        +----+-------------+---------+------------+------+-------------------+------+---------+------+------+----------+-------------+
        | id | select_type | table   | partitions | type | possible_keys     | key  | key_len | ref  | rows | filtered | Extra       |
        +----+-------------+---------+------------+------+-------------------+------+---------+------+------+----------+-------------+
        |  1 | SIMPLE      | teacher | NULL       | ALL  | idxtcid,idx_tname | NULL | NULL    | NULL |    6 |    44.44 | Using where |
        +----+-------------+---------+------------+------+-------------------+------+---------+------+------+----------+-------------+

8.一些其他的优化方法
        a.exist 和 in    
        如果主查询的数据集大,则使用 in
        如果子查询的数据集大,则使用exist

        b.order by 优化掉了
            >调整max_lenght_for_sort_buffer 大小,选择回表排序或非回表排序(需要排序的字段的总大小大于调整max_lenght_for_sort_buffer,则是回表排序\
            >避免 select *......
            >复合索引 不要跨列使用,避免using filesort
            > 保证全部的排序字段排序一致性(都是升序或降序)


结论:
1.id值相同,从上到下顺序执行,id值不同,从大到小顺序执行
2.system/const :结果只有一条数据
  eq_ref:结果多条,但是每条数据是唯一的
  ref:结果多条,但是每条数据时0或多条
3.using filesort 如何避免?
    单索引情况下: where 哪些字段就 order by 哪些字段
    复合索引情况: where + order by 的栏位 按照复合索引的顺序使用,不要无序或跨列使用
4.using temporary 如何避免?
    查询哪些列,就根据那些列group by
5.符合索引不要跨列、无需使用。
6.最佳左前缀,保持索引的定义和使用顺序要一致,不能跨列
7.索引需要逐步优化
8.将含 in 的范围查询,放到where 条件的最后,防止索引失效
9.两表连接时,索引往哪张表加?
    左外连接时(left outer join),给左边的表加索引,同理右外连接给右边的表加索引,总之就是在使用较频繁的字段上加索引,比如小表10条数据,大表100条数据,如果
    .. on 小表.c = 大表.c ,则小表的c字段每一条记录都要跟 大表.c 字段比对100次,故小表.c字段使用频繁,故在小表.c 字段上加索引
10.当编写 。。 on t.cid=c.cid 时,往往将数据量小的表放左边
11.小表驱动大表
12.exist 和 in,    如果主查询的数据集大,则使用 in,    如果子查询的数据集大,则使用exist
13.order by 优化
    >调整max_lenght_for_sort_buffer 大小,选择回表排序或非回表排序(需要排序的字段的总大小大于调整max_lenght_for_sort_buffer,则是回表排序\
    >避免 select *......
    >复合索引 不要跨列使用,避免using filesort
    > 保证全部的排序字段排序一致性(都是升序或降序)
14.尽量不要使用or,否则索引失效
15.尽量使用索引覆盖(using index)
16.like尽量以“常量”开头,不要以“%”开头,否则索引失效
17.不要类型转换(显示、隐士)
18.三张表优化。a.小表驱动大表;    b.索引建立在经常查询的字段上
19.避免索引失效的一些原则 
    (1)复合索引
        a.复合索引,不要跨列或无需使用(最佳左前缀,如果最左边失效,则后面的全部失效)
        b.复合索引,尽量使用全索引匹配
    (2)不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
        不要:select ... where a.x * 3 =
    (3)复合索引不能使用不等于(!= 或 <> ) 或 is null (is not null,否则自身以及右侧全部失效
    (4)体验概率情况(<  >  =):原因是服务层中有SQL优化器,可能会影响我们的优化。
20.将含 in 的范围查询,放到where 条件的最后,防止索引失效

----------------------------------------------------------------------------------------------------


SQL优化,主要就是索引优化
索引的弊端:
    1.索引本身很大,可以存放在内存/硬盘(通常为硬盘)
    2.索引不是所有情况均适用:
        a.数据量小  
        b.频繁更新的字段。因为如果索引字段频繁更新,则会导致索引的结构频繁变更,维护成本太高
        c.很少使用的字段。因为不需要查(或者很少查),所以不必建索引
    3.索引会降低增删改的效率。
        如果没有索引,则直接找到需要增删改的数据修改即可。
        如果有索引,不光要改数据,还有修改索引的结构,所以会影响增删改的效率。

优势:
    1.提高查询效率(实质就是降低IO使用率)
    2.降低CPU使用率(....order by .. asc/desc,因为B 树索引本身就是一个排好序的结构,因此在排序的时候可以直接使用)

 

如理解有误,请多指正,感谢!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_31144297/article/details/103778461

智能推荐

Spring Boot Admin2 实例状态监控详解-程序员宅基地

文章浏览阅读3k次,点赞108次,收藏158次。在微服务中集成Spring Boot Admin 的主要作用之一就是用来监控服务的实例状态,并且最好是当服务DOWN或者OFFLINE的时候发消息提醒,SBA2 提供了很多提醒方式,并且SBA2 已经集成了钉钉,只要进行少量配置即可将状态变更发送到钉钉_admin2

js验证注册页面(用户名、手机号、邮箱、单位名称、单位地址、联系人姓名、)_js校验公司名称-程序员宅基地

文章浏览阅读3.1k次。使用js+jQuery验证注册页面<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%><%@include file="/common/global.jsp"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML ..._js校验公司名称

xss漏洞java代码_Java处理XSS漏洞的工具类代码-程序员宅基地

文章浏览阅读694次。public classAntiXSS {/*** 滤除content中的危险 HTML 代码, 主要是脚本代码, 滚动字幕代码以及脚本事件处理代码**@paramcontent* 需要滤除的字符串*@return过滤的结果*/public staticString replaceHtmlCode(String content) {if (null ==content) {r..._xxs 漏洞替换特殊字符串 java

webstorm运行项目error:03000086错误的解决_webstorm --openssl-legacy-provider-程序员宅基地

文章浏览阅读307次。03000086 错误解决。_webstorm --openssl-legacy-provider

时间戳转time-t c语言,浅谈时间戳与日期时间互转C语言-程序员宅基地

文章浏览阅读395次。浅谈时间戳与日期时间互转C语言/** ctime.h** Created on: May 19,2016**/#ifndef CTIME_H_#define CTIME_H_#include "common/micro_type.h"#define OFFSET_SECOND 946684800 /* ��1970/1/1/0/0/0��2000/1/1/0/0/0֮��������� *//..._c time 时间点转换为time

无监督学习的应用在医学图像分析中-程序员宅基地

文章浏览阅读569次,点赞18次,收藏15次。1.背景介绍无监督学习是一种机器学习方法,它不需要预先标记的数据来训练模型。相反,它通过分析未标记的数据来发现数据中的模式和结构。在医学图像分析领域,无监督学习已经被广泛应用于许多任务,例如疾病诊断、病理诊断、医学影像分割等。无监督学习在医学图像分析中的主要优势是它可以自动发现隐藏的结构和模式,从而提高诊断准确性和效率。在这篇文章中,我们将讨论无监督学习在医学图像分析中的应用,以及它的核心...

随便推点

大数据时代带来智慧生活-程序员宅基地

文章浏览阅读174次。如何在大数据时代中把握大数据应用的机遇与挑战,智慧城市如何建设?昨日,上海大学兼职教授、华光大数据研究院院长蒋永生在本社展示、讲解了大数据应用以及给百姓生活带来的变化。  智慧城市从顶层设计起步  目前国内已有100多个城市提出智慧城市的构想,上海、成都、宁波和..._大数据时代下的数字化生活 蒋永生

每周一道算法题001:回文数-程序员宅基地

文章浏览阅读140次。题目:找出大于10的最小的2进制,8进制,10进制都是回文数的最小的数。回文数指的是正读和反读都是一样的数,例如:33,10001,123454321...思路:先转换进制,然后统一处理成字符串进行比较解答:PHPfunction execute(){ $x = 11; while (1) { if ($x == strrev($x) ..._如果字符串满足以下条件之一

Hotel experience Privacy Policy-程序员宅基地

文章浏览阅读58次。This application understands the importance of personal information to you and will do its best to protect the security and reliability of your personal information. We are committed to maintaining your trust in us and abide by the following principles to

【CTF】实验吧 奇怪的短信-程序员宅基地

文章浏览阅读874次。和实验吧 The Flash-14有些类似,总共的数字数目是偶数,所以两两分开,题干中的“短信”是提示,观察两两分组的第二个数字没有超过四的,可以想到手机上的九键例如第一组数:33 对应的是F,最后全部对应完,得到:FLAGISSIMPLE同样,大小写都试一遍,最后提交的是:CTF{flagissimple}...

【PyTorch深度学习项目实战100例目录】项目详解 + 数据集 + 完整源码_深度学习实战案例-程序员宅基地

文章浏览阅读7w次,点赞135次,收藏908次。大家好,我是阿光。本专栏整理了《深度学习100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。正在更新中~ 。_深度学习实战案例

【动画】【特效】 17种常用动画特效-程序员宅基地

文章浏览阅读386次。主Activity的布局文件xml<?xml version="1.0" encoding="utf-8"?><LinearLayout ="http://schemas.android.com/apk/res/android" android:id="@+id/widget33" android:..._动画特效 配电

推荐文章

热门文章

相关标签