sql 优化(二):explain 的使用方法和索引(主键索引/唯一索引/全文索引/普通索引/联合索引)

sql 测试代码

2)通过explain分析低效率的SQL语句的执行情况
1)索引
四种索引(主键索引/唯一索引/全文索引/普通索引)
添加
1.1主键索引添加
当一张表,把某个列设为主键的时候,则该列就是主键索引
create table aaa
(id int unsigned(无符号与有符号就是范围上的区别) primary key auto_increment ,
name varchar(32) not null defaul ‘’);
这是id 列就是主键索引.
如果你创建表时,没有指定主键索引,也可以在创建表后,在添加, 指令:
alter table 表名 add primary key (列名);
举例:
create table bbb (id int , name varchar(32) not null default ‘’);
alter table bbb add primary key (id);

查询表中的索引信息
Desc 表名  显示的就是索引的情况

Show index(es) from 表名或者Show keys from 表名


如果是在linux 命令行中为了看的更加的清楚
Show index(es) from 表名\G;


Eg:emp.frm 表示的emp 的表的结构,emp.MYD表示的是表的数据本身,emp.MYI 表示的是索引的大小,如果这个时候给这个表添加索引的话,这个时候文件的大小就变大了
1.2普通索引
一般来说,普通索引的创建,是先创建表,然后在创建普通索引
比如:
create table ccc(
id int unsigned,
name varchar(32)
)
create index 索引名 on 表 (列1,列名2);
给emp 表加了索引以后

查询时间大幅度缩短

二叉树的算法是如何写出来的
比如它要检索11 个数字
1234567891011  
写二叉树的写法,11 个树最中间的数是6写在根节点
小于6的一共有12345 这5个数的中间是3写在6的左侧,大于6的一共有7891011
这5个数的中间是9 写在6的右侧,比3小的写在3的左侧,比3小的只有1,2两个数字,向上取整就是向大的数取整,所以2在3的左侧,1比2小放在2的左侧,比3大的比6小的还有两个数字,5,4 向上取整是5,放在3的右侧,比5小的放在5的左侧,比9小比6大的还有两个,7,8 向上取整是8,放在9 的左侧,7比8小放在8的左侧,比9大的还有两个10,11 向上取整11 放在9的右侧,10比11小放在11的左侧
二叉树的比较的方法是
例如select * from emp where emp =4;
4直接和6比较,比6小的话比6大的所有的数就不用比较了,3和4比较比4大,那就和5比较,比5小,最后就找到了4,所以一共才比较了4次就找到了,二叉树的效率是2^n n是比较次数,2^n 就是它可以扫描的数的范围,所以二叉树的查询方式是非常快速的。

1.3创建全文索引

全文索引,主要是针对对文件,文本的检索, 比如文章, 全文索引针对MyISAM有用.

创建 :
CREATE TABLE articles (
       id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
       title VARCHAR(200),
       body TEXT,
       FULLTEXT (title,body) -- --如果只有这句话是不生效的只有针对myIsam 生效--
     )engine=myisam charset utf8; -- --全文索引针对MyISAM有用--

INSERT INTO articles (title,body) VALUES
     ('MySQL Tutorial','DBMS stands for DataBase ...'),
     ('How To Use MySQL Well','After you went through a ...'),
     ('Optimizing MySQL','In this tutorial we will show ...'),
     ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
     ('MySQL vs. YourSQL','In the following database comparison ...'),
     ('MySQL Security','When configured properly, MySQL ...');
查看是否有全文索引
Show indexes from article;


如何使用全文索引:
错误用法:
select * from articles where body like ‘%mysql%’; 【不会使用到全文索引】
证明没有用到全文索引:
explain  select * from articles where body like '%mysql%'

这个possible_key 是空的,索引没有用到全文索引
正确的用法是:
select * from articles where match(title,body) against(‘database’); 【可以】
 

可以看出来真的是可以找到database
Select match(title,body) against('database') from articles;显示的是在每一行查出来database
字符串的概率

扫描二维码关注公众号,回复: 2904348 查看本文章

只会是针对不太常用的词才会创建索引

Eg 常用的词不会创建索引,就像a字符串,查找的匹配度为0 ,就是没有创建索引,这种词叫做停止词。

Selectmatch(title,body) against('a') from articles;

利用sphinx (coreseek) 技术处理中文

1.4唯一索引

①当表的某列被指定为unique约束时,这列就是一个唯一索引

createtable ddd(id int primary key auto_increment , name varchar(32) unique);

这时, name 列就是一个唯一索引.

unique字段可以为NULL,并可以有多个NULL, 但是如果是具体内容,则不能重复.

Insertddd values(1,null);

Insertddd values(1,null);

是允许的,但是空字符串不能是认为是

主键字段,不能为NULL,也不能重复.

 

②在创建表后,再去创建唯一索引

createtable eee(id int primary key auto_increment, name varchar(32));

create unique index 索引名  on 表名 (列表..);

索引的添加是为了提高查询的速度,但是updatedelete insert 的速度会变慢

因为:这三种操作会破坏二叉树的,所以会造成速度变慢

在哪些列上适合添加索引?

唯一性太差的字段,比如说就只有两个性别,建立二叉树的时候全是平级的,找的时候就不适合建立索引,变化太多的例如字段的状态在一直变化

mysql 什么时候用单列索引?什么使用用联合索引?(收集)

我一个表 students 表,有3个字段 ,id,name,age 我要查询 通过 name 和age,在这两个字段 是创建 联合索引?还是分别在name和age上创建 单列索引呢? 多个字段查询什么情况下用联合索引 什么时候分别创建单列索引呢?

1,首先要确定优化的目标,在什么样的业务场景下,表的大小等等。如果表比较小的话,可能都不需要加索引。
2,哪些字段可以建索引,一般都where、order by 或者 group by 后面的字段。
3,记录修改的时候需要维护索引,所以会有开销,要衡量建了索引之后的得与失。

学生表,可以认为name的重复度比较小,而age的重复度比较大,对于单列索引来说,比较适合建在重读度低的列上。

对于select * from students where name='张三’and age=18; 题主所说的两种情况
A. name 和 age 各自单独建立索引。
一般来说mysql会选择其中一个索引,name的可能性比较大,因为mysq会统计每个索引上的重复度,选用低重复度的字段。另外一个age的索引就不会用到,但还有维护索引的开销,所以age的索引不需要创建。

B. name和age的联合索引
这种索引的切合度最好,mysql会直接选用这个索引。但相对单独的name索引来说,维护的成本要大一些,并且索引数据占用的存储空间也要更大一些。

回过来看,有必要使用联合索引吗? 我的看法是没有必要,因为学校里可能会有重名的人,但比较少。用name就可以比较精准的找到记录,即使有重复的也比较少。

什么情况下使用联合索引比较好呢? 举一个例子,大学选认课老师,需要创建一个关系对应表,有2个字段,student_id 和 teacher_id,想要查询某个老师和某个学生是否存在师生关系。
一个学生会选几十个老师,一个老师会带几百个学生
如果只为student_id建立索引的情况下,经过索引会选出几十条记录,然后在内存中where一下,去除其余的老师。
相反如果只为teacher_id建立索引,经过索引会选出几百条记录,然后在内存中where一下,去除其余的学生。
两种情况都不是最优的,这个时候使用联合索引最合适,通过索引直接找到对应记录。

创建索引实例:

首先创建一个表:create table students (id int primary key,name varchar(20),age Int);

创建单个索引的语法:create index 索引名 on 表名(字段名)

索引名一般是:表名_字段名

给id创建索引:create index students _id on students (id);

创建联合索引的语法:create index 索引名 on 表名(字段名1,字段名2) 
 

给name和age创建联合索引:create index students _name_age on students (name,age)

explain的使用方法

估算可能扫出来7条

explain 可以帮助我们在不真正执行某个sql语句时,就执行mysql怎样执行,这样利用我们去分析sql指令.
联合索引:
先创建存储过程,向dept 这张表中插入10条记录
create procedure insert_dept(in start int(10),in max_num int(10))
begin
declare i int default 0;
 set autocommit = 0;  
 repeat
 set i = i + 1;
 insert into dept values ((start+i) ,rand_string(10),rand_string(8));
  until i = max_num
 end repeat;
   commit;
 end
call insert_dept(100,10);
把dept表中,我增加几个部门:
使用联合索引:
alter table dept add index my_ind (dname,loc); //  dname 左边的列,loc就是右边的列,my_ind 是索引的名字,创建的是联合索引
1 只要查询条件使用了最左边的列,联合索引一般就会被使用。
explain select * from dept where loc ='aaa'

2查询条件用到了最右边的列,联合索引一般就不会被使用。

explain select * from dept where dname = 'aaa'

3对于使用like的查询,查询如果是  ‘%aaa’ 不会使用到索引
    ‘aaa%’ 会使用到索引。
比如: explain select * from dept where dname like '%aaa'
不能使用索引,即,在like查询时,关键的 ‘关键字’ , 最前面,不能使用 % 或者 _这样的字符., 如果一定要前面有变化的值,则考虑使用 全文索引->sphinx.

explain select * from dept where dname like 'aaa%'
explain select * from dept where dname like 'aaa'
explain select * from dept where dname like 'a_aa'

所以要用全文索引要替代模糊查询,由于模糊查询时的就是不能把%放到前面去,如果一定要前面有变化时一定要全文索引。
4如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引, 我们建议大家尽量避免使用or 关键字
select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45
1)select * from dept where dname=’xxx’ or loc=’xx’

实际上没有用到索引,由于loc 是联合索引右面,联合索引不生效。
2)select * from dept where dname=’xxx’ or loc=’xx’ or deptno=45

实际上没有用到索引,由于loc 是联合索引右面,联合索引不生效。

explain select * from dept where dname='xxx' or  deptno=45

这个时候是两个索引都生效了,只要是有一个不带索引都是不行的
6如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引。(添加时,字符串必须’’), 也就是,如果列是字符串类型,就一定要用 ‘’ 把他包括起来,即使查询的是字符串也要用单引号包括起来
explain select * from dept where dname='45'
7如果mysql估计使用全表扫描要比使用索引快,则不使用索引。
如何查看索引使用的情况:
show status like ‘Handler_read%’;

handler_read_key:这个值越高越好,越高表示使用索引查询到的次数。
handler_read_rnd_next:这个值越高,说明查询低效。
大批量插入数据(MySql管理员) 了解
对于MyISAM:
alter table table_name disable keys;//先把索引禁用了,要不会影响插入的效率
loading data//insert语句;
alter table table_name enable keys;//插入完数据以后,再启用
对于Innodb:
1,将要导入的数据按照主键排序
2,set unique_checks=0,关闭唯一性校验。
3,set autocommit=0,关闭自动提交。

优化group by 语句
注意:在使用group by 语句的时候没有使用索引

由上面可以知道,默认情况,MySQL对所有的group by col1,col2进行排序。这与在查询中指定order by col1, col2类似。如果查询中包括group by但用户想要避免排序结果的消耗,则可以使用order by null禁止排序
在group by 后面增加 order by null 就可以防止排序.

有些情况下,可以使用连接来替代子查询。因为使用join,MySQL不需要在内存中创建临时表。
select * from dept, emp where dept.deptno=emp.deptno; [简单处理方式]
select * from dept left join emp on dept.deptno=emp.deptno;  [左外连接,更ok!]

猜你喜欢

转载自blog.csdn.net/qq_20610631/article/details/82056966