Mysql优化

一.表结构优化
二.列类型优化
三.索引优化策略
四.聚簇索引和非聚簇索引
五.理想的索引

怎么查看一个sql语句的执行效果

    在sql语句前面加上 “explain”,如果加上"\\\\G",则能看到竖列效果   explain  sql   \\\\G    
    结果中的 key_len 就是在查询上所用到的索引的个数; using filesort就是用到了排序的意思;using index是用到了索引覆盖
    排序非常耗资源,想分组,必须排序
    测试运行需要的时间   time  file.php
    如果A\\\\B两张表结构是一样的,把A表里面的数据插入B表,
    可以这样执行:insert into B select * from A;
    如果要插入某个字段的数据
    insert into B select id,name,age from A;

   在数据库终端指令, 如果要查看前几个 sql语句运行时间,show profiles;这个时候只能看到小数点后两位,
    如果要看到精确的运行时间。set profiling = on;
    如果某个表查询的时候出现了乱码,在终端 set names utf8;
    delimiter $   //在终端输入$才会结束一条语句

优化总则
1.少查(能不查就不查)
2.查少(少查点数据)
3.快点查(走索引)
4.少排序

一.表结构优化

1.定长和变长分离

  如id int,占4个字节,char(4)占4个字段长度,也是定长,time 即每一个单元值占的字节是固定的
  而varchar,text,blob,这种变长字段,适合单放一张表,用主键与核心表关联起来

2.常用字段和不常用字段分表,通过uuid将两张表关联。这个需要结合网站的具体业务来分析,分析字段的查询场景,查询频率低的字段,单拆出来(用空间来换取时间)

    比如两张关联表,一个是板块表(cat),另一个是板块下回复的帖子。查询某个板块下有多少个回复
    方法一:先查出有几个板块,再在for循环里面找每个板块下有多少回复
    select * from cat;  //比如10个板块
    for($i=1; $i<=10; $i++){
      select count(*) from post where cat_id = $i;
    }
    方法二,使用左右连接查询,比较消耗资源,不推荐
    select cat.* from cat left join post on cat.cat_id = post.cat_id group by cat_id;
    如果我们需要实时计算帖子的数量,可以在cat表里面再加一个num字段,每次有人发帖,让这个字段用update更新加1,这是最好的方法。

二.列类型优化

字段类型选择原则
整型>date,time,>enum,char>varchar>blob,text

    列的特点分析:
    整型:定长,没有国家/地区之分,没有字符集的差异
    比如,tinyint 1,2,3,4,5 <--> char(1) a,b,c,d
    从空间上,都是占1个字节,但是order by排序,前者快
    原因:char需要考虑字符集与校对级(就是排序规则)
    time 定长,运算快,节省空间,考虑时区时,写sql时不方便 where > '2016-10-11';
    enum:定长,能起约束的目的,内部用整型来存储,但与char联查时,内部要经历串与值得转化
    Char 定长,考虑字符集的转换与排序时的校对集
    varchar,不定长,要考虑字符集的转换与排序时的校对集,速度慢
    text/blob,无法使用内存临时表(排序等操作只能在磁盘上进行)

三.索引优化策略

1.索引类型
1.1Btree索引(二叉树就是索引)--适用于范围的查询

    名叫btree索引,大的方面看,都是用的平衡树,但是具体的实现上,各引擎稍有不同
    比如,严格说NDB引擎,使用的是T-tree
    Mysiam,innodb中默认使用B-tree
    但抽象一下,B-tree系统可以理解为"排好序的快速查找结构"

1.2hash索引(只在内存表里面使用hash索引)

    在memory表里默认是hash索引,hash里的理论查询时间复杂度为0(1)(一次就能找到)
    hash的特点:
    1.随机性:hash函数计算后的结果,是随机的,如果是在磁盘上放置数据,
      比如主键为id,那么随着id的增长,id对应的行,在磁盘上随机放置
    2.无法对范围查询进行优化
    3.(离散性)无法利用前缀索引,比如在btree中,field列的值"helloworld",加索引, hash(helloworld)和hash(hello),两者没有关系。
    4.排序也法优化(它是随机分配数据的)
    5.必须回行,也就是说,通过索引拿到数据位置,必须回到表中取数据

2.btree索引常见的误区

    要查询的字段都建立了索引,并不是都可以使用得到。查询的时候遵循左前缀规则

2.索引的左前缀规则--比如index(a,b,c)

语句 索引是否发挥作用
where a=3 是,只使用了a列
where a=3 and b=5 是,只用了a,b列
where a=3 and b=5 and c=4 是,使用了abc列
where b=3 / where c=4
where a=3 and c=4 a列能发挥索引,c不能
where a=3 and b>10 and c=7 A能利用,b能利用,c不能利用
同上,where a=3 and b like"xxx%" and c=7 A能利用,b能利用,c不能利用

四.聚簇索引和非聚簇索引

Myisam用的是非聚簇索引:主键和次索引都指向物理行磁盘的位置

    数据是数据 独立文件 xx.myd
    索引是索引 独立文件 xx.myi
    两者不掺和 这就是非聚簇
    它的查找是先根据索引查找到主键的值,值旁边有一个地址,在地址上去查找你要的信息,这个过程叫“回行”。
    但是innodb聚簇,值得旁边直接就是行信息。这就是他们的本质信息

innodb用的是聚簇索引:innodb的主索引文件上,直接存放该行数据,称为聚簇索引,次索引指向对主键的作用

    注意:对innodb来说
    1.主键索引  既存储索引,又在叶子中存储行的数据
    2.如果没有主键(primary key),则会unique key做主键
    3.如果没有unique,则系统生成一个内部的 rowid 做主键
    4.像innodb中,主键的索引结构中,既存储了主键的值,又存储了行数据,这种结构称为"聚簇索引"

聚簇索引
优势:根据主键查询条目比较少时,不用回行(数据就在主节点下)
劣势:如果碰到不规则数据插入时,造成频繁的页分裂

索引覆盖
索引文件中,myi有你需要的字段,就不需要回行。这就是索引覆盖

    explain sql \\\\G   如果在extra里面出现了"using index",就是用了索引覆盖,查询效率会很高
    比如:如果表A中c1建立了索引
    explain select c1 from A where c1>5 \\\\G;  这个时候就用到了索引覆盖
      explain select c1,c2 from A where c1>5 \\\\G;如果c2没有索引  这个时候没用索引覆盖。因为c2在索引里面找不到,需要回行

五.理想的索引

     1. sql查询中也可以直接使用函数,例如查询词典表中最长的两个单词:
    select  * from dict order by length(word) desc limit 2;

    2.取10个,单词的左边只有一个值的:
    select   left(word,1)  from dict limit 10;
    3.取重复的
    select  distinct left(word,1)  from dict limit 10;
    select count( distinct left(word,1) ) from dict;

2.伪哈希索引技巧
用于存储url,有两种方法。1,列内容倒过来存储并建立索引。这样左前缀区分度大。

    2.伪hash索引效果同时存url hash列
    create table A( id int primary key,
            url char(60) not null default '' );
    insert into A values(1,"www.baidu.com"),
    (2,"www.sina.com"),(3,"www.itxdl.com");
    alert table A add urlcrc int unsigned not null;

    在sql存储时,crccurl == crc32(url)
    因为crc的结果是32位,int 无符号数,因此当数据超过40亿也会有重复,但这是是的的。(索引长度为int4个字节)
    select crc32('str');  //可以把任何字符串转换成数字

    商品建立索引,一般两种方式
    以,栏目、价格 index(cat_id, price); 或者栏目、品牌、价格 index(cat_id,brand_id,shop_price);

索引与排序有两种情况
1.对于覆盖索引,直接在索引上查询时,就是有序的,using,index
在innodb引擎中,沿着索引字段排序,也是自然有序的,对于myisam引擎,如果按某种索引字段排序,如id,但去除的字段中未有索引字段,如goods_name,myisam的做法,不是 索引->回行,而是先去除所有的行,再进行排序
2.先去除数据,形成临时表做filesort(文件排序,但文件可能在磁盘上,也可能在内存中)

你可能感兴趣的:(Mysql优化)