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

智能推荐

从零开始搭建Hadoop_创建一个hadoop项目-程序员宅基地

文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目

心脏滴血漏洞HeartBleed CVE-2014-0160深入代码层面的分析_heartbleed代码分析-程序员宅基地

文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析

java读取ofd文档内容_ofd电子文档内容分析工具(分析文档、签章和证书)-程序员宅基地

文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat

基于FPGA的数据采集系统(一)_基于fpga的信息采集-程序员宅基地

文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集

微服务 spring cloud zuul com.netflix.zuul.exception.ZuulException GENERAL-程序员宅基地

文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception

邻接矩阵-建立图-程序员宅基地

文章浏览阅读358次。1.介绍图的相关概念  图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为:  G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图

随便推点

MDT2012部署系列之11 WDS安装与配置-程序员宅基地

文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc

python--xlrd/xlwt/xlutils_xlutils模块可以读xlsx吗-程序员宅基地

文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗

关于新版本selenium定位元素报错:‘WebDriver‘ object has no attribute ‘find_element_by_id‘等问题_unresolved attribute reference 'find_element_by_id-程序员宅基地

文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver

DOM对象转换成jQuery对象转换与子页面获取父页面DOM对象-程序员宅基地

文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象

什么是算法?-程序员宅基地

文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法

【网络安全】网络安全的标准和规范_网络安全标准规范-程序员宅基地

文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范