zoukankan      html  css  js  c++  java
  • mysql优化

    0 内容

    1.mysql底层原理:逻辑分层、数据库引擎

    2.sql优化:sql优化和索引的关系

    3.索引

    4.sql性能问题,优化方法

    5.优化案例

    6.避免索引失效的一些原则

    7.一些其他优化方法

    8.sql排查----慢查询日志

    9.分析海量数据

    10.锁机制:解决因资源共享 而造成的并发问题

    11.主从复制:将主数据库同步到从数据库

    mysql版本

    1.主流的是5.x版本。

    5.4-5.x用的最多。特点:整和了三方公司的新存储引擎。(其中5.5最多。)

    2.安装mysql

    rpm -ivh rpm软件名(自己网上下载的rpm

    如果安装过程中与某个软件冲突,就将其卸载掉

    yum -y remove  xxx

    启动mysql应用:service mysql start

    关闭: service mysql stop

    重启: service mysql restart

    当出现mysql.sock不存在的报错时,可能原因时mysql服务没有启动,此时设置开机自动开启mysql服务:

    开机自启:chkconfig mysql on

    取消开机自启:chkconfig mysql off

    root用户设置密码

    /usr/bin/mysqladmin -u root password 123

    数据库存放目录查看:

    ps -ef|grep mysql  可以看到数据存放目录和pid文件目录

    mysql的核心目录:

    /var/lib/mysql   mysql的安装目录

    /usr/share/mysql     mysql的配置文件

    /usr/bin  命令目录(mysqladminmysqldump等命令)

    /etc/init.d/mysql   mysql启停脚本

    mysql配置文件:

    常见

    my-huge.cnf 高端服务器(1-2G内存)的配置在这里面配

    my-large.cnf      中等

    my-medium.cnf 一般

    my-small.cnf 较小

    但是,以上配置文件mysql不能默认识别。默认只能识别/etc/my.cnf。因此要将上面的配置复制一份为my.cnf

    cp /usr/share/mysql/my-huge.cnf  /etc/my.cnf

    注意:mysql5.5的默认配置文件为my.cnf,  5.6mysql-default.cnf

    mysql的字符编码:

    show variables like ‘%char%’;   查看编码

    可以发现部分编码为latin的,要统一设置为utf-8

    设置编码:

    vim /etc/my.cnf

    [mysql]标签下加入:

    default-character-set = utf8

    然后在[client]标签下加入default-character-set = utf8

    [mysqld]标签下加入:

    character_set_server = utf8

    character_set_client = utf8

    collation_server = utf8_general_ci

    注意:修改编码只对之后创建的数据库生效。因此建议在mysql创建后就改变编码。

    mysql清屏:

    ctrl+L 或者system clear     ----->linux

    一.mysql分层、存储引擎

    1.mysql逻辑分层

    连接层--------->服务层--------->引擎层--------->存储层

    客户端查询select命令,交给客户端的第一层连接层,连接层作用是提供与客户端连接的服务,只负责连接,不处理sql语句。然后到第二层服务层。服务层作用有两个:(1)提供各种用户使用的接口(select...);(2)提供sql优化器(优化器好处是对sql语句进行优化,提高性能,弊端是开发时写的和执行是不一致的,造成混乱)。其次到第三层引擎层,引擎层作用是提供各种存储数据的方式(InnodbMyisam等)。最后到第四层存储层,存储层作用是存储数据。

    2.存储引擎

    InnodbMyisam主要区别:Innodb是事务优先(防止并发操作问题),适合高并发操作,用的行锁;Myisam是性能优先,用的表锁。

    查询数据库引擎: 支持哪些引擎

    show engines

    show variables like ‘%storage_engine%’   查看当前使用引擎

    指定数据库对象的引擎:

    create table td(

    id int(4) auto_increment,

    name varchar(5),

    dept varchar(5),

    primary key(id)

    )ENGINE=MyISAM AUTO_INCREMENT=3(指定自增的步长)DEFAULT CHARSET=utf8 ;     #注意是在;内部

    二、sql优化

    1.sql优化

    1)为什么要sql优化:

    性能低、执行时间太长、等待时间太长、sql语句欠佳(连接查询)、索引失效、服务器参数设置不当(缓冲、线程等)

    2sql语句

    编写过程:

    select distinct ... from ...join ... on ... where ... group by ... having ... order by ...limit ...

    解析过程:(解析过程和编写过程不一致)

    from--->on---->join---->where--->group by---->having---->select distinct---->order by---->limit

    https://www.cnblogs.com/annsshadow/p/5037667.html

    2.sql优化与索引关系

    sql优化,主要就是在优化索引。

    索引:相当于书的目录。加速查询效率。索引是帮助mysql高效获取数据的数据结构(树:B树(mysql默认)、hash...)。

    索引弊端:

    本身很大,可以存在硬盘里面,占据一定空间

    不是所有情况都适用:少量数据;频繁更新的字段;很少使用的字段

    索引确实会提高查询的效率,但降低增删改的操作。(要改两次,还要改索引)

    索引优势:

    提高查询效率。(降低IO使用率)

    降低CPU使用率(比如....order by  有索引就自动给排好序了。)

    三、索引

    1.B

    3B树可以存放上百万数据。B树一般指B+树,真实数据存放在叶节点中,根节点和支节点的数据是关键字,只是为了分界指针,指引下一次查找方向的。

    B+树中查询任意数据次数都是n次。nB树的高度。

    2.索引分类:

    主键索引:不能重复,并且不能为null

    唯一索引:不能重复。一般用唯一标识符id。 和主键的区别是可以为null

    单值索引:单列,一个表可以有多个单值索引

    复合索引:多个列构成的索引(相当于二级目录) nameage) 先根据name找,name重复了再根据age找。(前面列找到唯一了,后面就可以不用找了)

    3.索引命令

    创建索引:

    方式一

    create 索引类型 索引名 on 表(字段)

    单值:create index dept_index on tb(dept);

    唯一:create unique index name_index on tb(name);

    复合:create index dept_name_index on tb(dept, name);

    方式二:

    alter table 表名 索引类型 索引名(字段)

    单值:alter table db add index dept_index(dept);

    唯一:alter table db add unique index name_index(name);

    复合:alter table db add index dept_name_index(dept, name);

    主键:alter table db add constraint tid_pk primary key(tid);

    注意事项:如果一个字段是主键primary key,该字段默认是 主键索引。

    删除索引:

    drop index 索引名 on 表名;

    drop index name_index on tb;

    查询索引

    show index from 表名;

    四、sql性能

    1.explain

    分析sql的执行计划:explain可以模拟sql优化器执行sql语句,从而让开发人员知道自己编写的sql状况。

    注:mysql查询优化器会干扰我们的优化

    2.explain字段

    id: 编号

    select_type :查询类型

    table :表

    type :类型

    possible_keys :预测用到的索引

    key :实际使用的索引

    key_len :实际使用索引的长度

    ref :表和表之间的引用关系

    rows: 通过索引查到的数据量

    Extra:额外的信息

    1id

    *id值相同,按照table表,从上往下执行(上面的表是数据量小的表)。

    多表查询

    表的执行顺序因数据量的个数改变而改变的原因:

    笛卡儿积。

    a b c 表分别是2 3 4 笛卡尔积为 2*3=6*4 =24

    当顺序变为3 4 2时,笛卡儿积为 3*4=12*2 =24

    虽然最终结果相同,但中间生成的表大小不一样。第一个为6,第二个为12.因此第一个耗的内存少。(程序喜欢中间过程越小越好)

    因此数据量小的先算,数据量大的后算,这样中间生成的表小。

    总结来说,就是数据量小的表优先查询。

    *id值不同,id值越大越优先被查询

    子查询

    本质:在嵌套子查询时,先查内层,再查外层

    *id值有相同,又有不同:id值越大越优先被查询,id值相同时从上往下执行。

    2select_type

    primary :包含子查询sql中的主查询(最外层)  sql语句的核心语法。

    subquery:包含子查询sql中的子查询(非最外层)

    simple:简单查询(不包含子查询、union查询)

    derived:衍生查询(在查询的时候用到了临时表)

    情况1:在from子查询中只有一张表 ,from里这张表是derived衍生查询。

    explain select cr.cname from (select * from course where tid in (1,2)) cr;

    因为cr是临时产生的。

    此时primary后面的table写的<derived2>表示主查询涉及到衍生表,id2

    情况2:在from子查询中,如果有table1 union table2 ,table1就是衍生表derivedtable2union

    union:见上例。

    union result:告知开发人员,哪些表之间存在union查询。

    3type索引类型

    system > const > eq_ref >ref > range > index >all

    >表示性能。越往左边,性能越高。

    其中systemconst只是理想情况,实际达不到。实际能达到 ref > range 。不优化,就是all

    要对type优化的前提:有索引。

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

    const: 仅仅能查到一条数据的sql必须用于主键索引或者唯一索引。(类型  索引类型有关)

    eq_ref: 唯一性索引:对于每个索引键的查询,返回匹配唯一行的数据(有且仅有一个)。常见于主键索引和唯一索引。也很难满足,要求查询结果和数据条数是一致的。表的数据的个数和连接查询的数据个数一致(查出来的数据和实际数据个数是一样的),有可能满足eq_ref,否则不能满足(肯定有0的记录)

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

    range:检索指定范围的行, where后面是个范围查询。(between><in注:in有时会失效,从而转为无索引all

    (在查询前先确定是索引,否则谈不上优化,都是all

    index:查询全部索引中的数据。只将索引树全查了一遍。(索引字段的数据)

    比如:explain select 索引 from table

    all:查询全部表中的数据。将整个表的数据查了一遍。(所有字段的数据)

    比如:explain select 非索引 from table  #不是索引,全扫描

    type类型总结:system/const:结果只有一条数据;eq_ref:结果多条,但每条数据是唯一的 ;ref:结果多条,但每条数据是0或者多条。

    4possible_keys 可能用到的索引

    是一种预测。如果是null,说明没用索引

    5key 实际索引。如果是null,说明没用索引

    6key_len : 索引长度 用于判断复合索引是否被完全使用。(abc)可能只用到abc没用。(key_len(字节)和索引的实际长度(字符))

    utf8中一个字符占3个字节。(比如索引的字段(非空的)是char(20),是20个字符,但实际占据60个字节,因此在key_len中查出来的是60

    如果索引字段可以为null,在mysql会使用一个字节用于标识。比如索引的字段(可以为空的)是char(20),是20个字符,但实际占据60+1个字节,因此在key_len中查出来的是61

    如果是varchar(20)varchar是可变字符(char是固定长度字符),那么explainkey_len为字节63=20*3 + 1(可以为空的标识) + 2(可变长度的标识)

    utf8 1字符3字节

    gbk1字符2字节

    latin1字符1字节

    7ref

    注意与type中的ref区分。作用:指明当前表所参照的字段。

    select .... where a.c = b.x(其中b.x可以是常量,,const)   b.x就是参照的字段

    rows

    被索引优化查询的 数据个数(实际通过索引而查询到的数据个数)

    8extra

    常见:

    using filesort: 标识性能消耗比较大。需要‘额外’一次排序(查询)。排序 的前提是先先查询。经常出现在order by

    对于单索引,如果排序和查找是同一个字段,则不会出现using filesort;反之,如果排序和查找不是同一个字段,会出现using filesort

    explain select * from test01 where a1=’’ order by a2   #a1a2是单索引。(要根据a2排序,而前面查的不是a2,因此需要一次额外的a2的排序操作)

    对于复合索引,不能跨列(最佳左前缀)。否则出现using filesort

    explain select * from test01 where a1=’’ order by a3(a1, a2, a3)

    a1 ,a3中间跨列了;a2,a3不符合最佳左前缀------》就会出现using filesort

    a1a2不会出现using filesort。(没有跨列,也符合最佳左前缀)

    建议:对于单索引,where哪些字段,就order by哪些字段。对于复合索引:where order by按照复合索引的顺序使用,不要跨列或者无序使用

    using temporary:用到了临时表,需要额外再多使用一张表

    性能损耗比较大,一般出现在group by分组。查根据一个字段,而分组却根据另外一个字段,就会出现这个问题。查到的表不适用,需要再查一张临时表。

    避免:查询哪些列,就根据那些列分组。

    要研究using temporary,先要知道解析过程:

    from--->on---->join---->where--->group by---->having---->select distinct---->order by---->limit

    using index: 性能提升了;索引覆盖。原因在于:不读取原文件,只从索引文件中获取数据,不需要回表查询(只查索引表)。

    只要使用到的列 全部都在索引中,就是索引覆盖。 using index

    如果用到索引覆盖(using index)时会对possible_keyskeys造成影响:如果没有where,则索引只出现在key中;如果有where,则索引出现在possible_keykey中。

    using where:需要回表查询

    既要从索引表查,又要回原表查,就会出现using where

    比如age是索引列

    但查询语句是select age, name from ... where age=... 此语句必须回原表查name,因此会显示using where

    impossible where where子句永远为false

    五、优化例子

    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,'tj', 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);

    commit

    查询authorId=1typeId23 bid

    select bid from book where typeId in(2,3) and authorId=1 ;

    explain select bid from book where typeId in(2,3) and authorId=1 ;

    explain select bid from book where typeId in(2,3) and authorId=1  order by typeId desc;

    上面语句必须要优化,typeall,又没有索引,又要文件内排序。

    优化:加索引。

    alter table book add index idx_bta(bid, typeId, authorId);

    比刚才有提升,但并不是很好。

    上面加索引的顺序和个数不对。 按照执行顺序,先where然后select。因此要调整索引的顺序

    索引一旦进行升级优化,要将之前废弃的索引删掉,防止干扰。

    drop index 索引名 on 表名;

    drop index idx_bta on book;

    alter table book add index idx_tab(typeId, authorId,bid);  虽然可以回表查询bid,但是将bid放到索引中,可以使用using index

    再次优化(现在typeindex,要再往上):

    explain select bid from book where typeId in(2,3) and authorId=1  order by typeId desc;

    in有时会导致索引失效,导致后面的索引也会失效。所以把等值的放前面(查询语句改变),范围查询的放后面

    查询语句变为:

    explain select bid from book where authorId=1 and typeId in(2,3) order by typeId desc;

    drop index idx_tab on book;

    alter table book add index idx_atb( authorId,typeId,bid);   处理索引

    提高了两个级别。

    注:上面的using where(回表)和using index(不回表)同时出现,即又要回表又要不会表,是不矛盾的。authorId在索引中,查表时索引里有,就不需要回表。而typeId虽然在索引中,但In 的范围查询使索引失效,因此typeId需要回原表。

    小结:

    1.索引不能跨列使用(最佳左前缀),保持索引的定义和使用顺序一致性。

    (跨列:原来顺序是abc,那么使用ac就是跨列。)

    1. 索引需要逐步优化
    2. 将含in的范围查询放到where的最后,防止失效。

        

       

    2.双表优化

    建表插数据

    create table teacher2(

      tid int(4) primary key,

      cid int(4) not null

    );

    insert into teacher2 values(1,2);

    insert into teacher2 values(2,1);

    insert into teacher2 values(3,3);

    create table course2(

      cid int(4),

      cname varchar(20)

    );

    insert into course2 values(1, 'java');

    insert into course2 values(2, 'python');

    insert into course2 values(3,'kotlin');

    commit;

    左连接:

    select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';

    优化加索引,索引往哪加呢(哪张表的字段加)

    -小表驱动大表where 小表.x =大表.x   

    小表:10条数据

    大表:300条数据

    select .... where 小表.x10=大表.x300;

    不管小表在前还是大表在前,最终结果是一样的,但是小表在左,就会使外层循环小。

    编程语言优化原则(外层放循环次数小的,内层放循环次数大的,性能越好)

    当编写on t.cid=c.cid类似语句时,将min(t, c)数据量小的表放左边。(假设t的数据量小)

    -索引建立在经常使用的字段。

    本题左边表(小表)的使用量大,因为每一条数据都要执行300次,因此给小表的x字段加索引。因此t.cid使用更频繁,给它加索引。

    一般情况,对于左外连接,给左表加索引;右外连接,给右表加索引。(因为左外连接的前提就是以左表为基础,左表的所有数据要全部匹配,也就是小表,即使用频繁;同理右表)

    不加索引的情况:

    explain select * from teacher2 t left outer join course2 c on t.cid=c.cid where c.cname='java';

    加索引:

    alter table teacher2 add index index_teacher_cid(cid);

    还有,where后面 等值的加个索引

    alter table course2 add index index_course2_cname(cname);

    using join buffer:extra中的一个选项,作用是:引擎使用了连接缓存。说明sql写的太差了。

    3.三表优化

    原则:

    小表驱动大表(小表放左边,大表放右边)

    索引建立在经常查询的字段(将where后面的字段和常用的几个字段加索引)

    六、避免索引失效的原则

    1.复合索引,不要跨列或无序使用(最佳左前缀)

    where a... and b... order by c  

    2.复合索引,尽量使用全索引匹配(索引建了,全用上)

    3.不要在索引上进行任何操作(计算、函数、类型转换等),否则索引失效

    select ... where A.x=..    假设A.x是索引

    不要select ... where A.x*3=...

    对于复合索引,如果左边索引失效,那么右边索引全部失效。(独立的索引没有关系)

    1. 复合索引不能使用不等于,或is nullis not null),否则自身以及右侧索引失效

        

       sql优化,是一种概率层面 的优化(服务层的优化器会动sql语句。至于是否实际使用了我们的优化,需要通过explain去推测。

       比如<时改了个数字,索引结果完全不同。(一个是ALL,一个是用了一个索引)

       索引优化是一个发部份使用的结论,但由于sql优化器的原因,结论不是100%正确。

    一般情况下,范围查询(>, < in),之后的索引失效。

      补救:尽量使用覆盖索引using index

      (a, b, c

    比如:select a,b,c from xxx where a=... and b=...;

     

    1. like尽量以常量开头,不要以%开头,否则索引失效。

        如果必须使用%开头进行模糊查询,可以使用索引覆盖(查询的列全部在索引里,不需要回表查询)挽救一部分。

    1. 尽量不要使用类型转换(隐式、显式),否则会使索引失效

    where tname = 123    tname类型是字符串,而查询时给的是数字,mysql在内部会转换,因此失效。

    1. 尽量不要使用or,否则失效。将or左侧也弄失效了。

               

    七.其他优化案例和总结

    1.优化例子

    建表和索引

    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_a1_a2_a3_a4(a1,a2,a3,a4);

    explain执行计划:

    explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a3=3 and a4=4;  推荐写法(索引使用顺序(where后面的顺序)和复合索引的顺序一致)

    explain select a1,a2,a3,a4 from test03 where a4=1 and a3=2 and a2=3 and a1=4; 和上面结果一致。虽然编写顺序和索引顺序不一致,但sql优化器调整了顺序,二者是等价的。不推荐。

    explain select a1,a2,a3,a4 from test03 where a1=1 and a2=2 and a4=4 order by a3;

    using index 代表一部分不需要回表操作。用到了a1a2两个索引。

    using where代表有回表操作。a4跨列使用,造成该索引失效,需要回表查询。

    key_len8也说明只用上了2个索引

    explain select a1,a2,a3,a4 from test03 where a1=1 and a4=4 order by a3;

    以上sql出现using filesort(文件内排序,多了一次额外的查找/排序)。原因是:不要跨列使用(whereorder by拼起来不要跨列使用)。

    解释上面拼起来:

    where a1=1 and a2=2 and a4=4 order by a3;   此时a4失效,则是a1, a2 ,a3,满足索引顺序

    where a1=1 and a4=4 order by a3;   此时a4失效了,则是a1a3,但跨列了,因此出现using filesort(看order by之后的索引和之前的索引是否跨列)

    比如:

    explain select a1,a2,a3,a4 from test03 where a1=1 and a4=4 order by a2; 就不会出现using filesort

    总结:

    1.如果(a,b,c,d)复合索引 和使用的顺序(where后面)全部一致且不跨列使用,则复合索引全部使用。如果部分一致,则使用部分索引。

    比如where a= and b= and c= and d=  使用全部索引

    where a= and b= and d=   部分一致,使用(a,b)

    where a= and b= and d=  and c =     部分一致,使用(a,b,c)

    2.whereorder by拼起来不要跨列,否则有文件内排序

    2.一些其他优化方法

     existin

    select ... from ... where exist (子查询);

    select ... from .... where 字段 in (子查询)

    如果主查询的数据集大(相对子),使用in

    如果子查询的数据集大,使用exist

    可以互相转换,只是遵循上面原则更高效

    exist语法:将主查询的结果,放到子查询结果中进行条件校验(看子查询是否有这个数据)。如果符合校验,则保留数据;

    select tname from teacher where exists (select * from teacher);

    -----》等价于select tname from teacher

    in语法:

    select ... from .... where 字段 in (1,3,5)

    select * from A where id in (select id from B);   //(1,3,5)

     

    order by优化

    using filesort 有两种算法:双路排序、单路排序(根据IO次数)

    mysql4.1之前默认使用双路排序;双路:扫描两次磁盘(第一次扫描排序字段,从磁盘读取排序字段后,进行排序(在buffer缓冲区进行的),第二次扫描其他字段)----->IO消耗性能

    mysql4.1之后默认使用单路排序;单路:扫描一次磁盘(全部字段),在buffer中排序。但单路排序有一定隐患(不一定真的是一次IO:数据量太多,则无法将所有的字段的数据一次性读取完毕,因此会进行“分片读取”。buffer可能放不下)

    注意:单路排序比双路排序占用更多的buffer

    单路排序在使用时,如果数据大,可以考虑调大buffer的大小。

    调节buffer大小:

    set max_length_for_sort_data = 1024 单位:字节

    如果set max_length_for_sort_data太低,会自动从单路切到双路。

    太低:需要排的列的总大小超过set max_length_for_sort_data定义的字节数。

     

    提高order by查询的效率:

    a.选择使用单路或者双路;调整buffer容量的大小

    b.避免select *

    c.复合索引不要跨列使用,避免using filesort

    d.尽量保证全部的排序字段 排序的一致性(都是升序 或者降序)

    八.sql排查:慢查询日志

     就是mysql提供的一种日志记录,用于记录mysql中响应时间超过阈值的sql语句。(long_query_time默认10s)。10s钟还没查出来,就说明急需优化。

    慢查询日志默认关闭的,建议:开发调优时打开,而在最终部署时关闭。

    检查是否开启 慢查询日志:

    show variables like '%slow_query_log%';

    开启慢查询日志:

    临时开启:set global slow_query_log = 1;    在内存里开启

    永久开启:配置文件my.cnf中追加:

    mysqld后追加:

    slow_query_log=1

    slow_query_log_file=目录/localhost-slow.log

    修改慢查询阈值:

    show variables like ‘%long_query_time%’;  查看

    临时修改阈值:

    set global long_query_time =5;   ---设置完毕后,重新登陆才生效。

    永久设置阈值:

    配置文件my.cnf中追加:

    mysqld后追加:

    long_query_time =5

    查询超过阈值的sql语句:

    show global status like ‘%slow_queries%’ ;

    慢查询的日志被记录到日志里面,可以通过查看日志 找到具体的mysql

    或者:
    通过工具mysqldumpslow查看 mysqldumpslow --help  选项方便查找

    s:排序方式

    r:逆序

    l:锁定时间

    g:正则匹配模式

    比如:

    获取返回记录最多的3sql

    mysqldumpslow -s r -t 3 日志文件绝对路径    #在终端中写的

    获取访问次数最多的3

    mysqldumpslow -s c -t 3 日志文件绝对路径   按照时间排序,并且前10条包含left join的查询语句sql

    mysqldumpslow -s t -t 10 -g ‘left join’ 日志文件绝对路径   

    语法:mysqldumpslow 各种参数 日志文件绝对路径   

    九、海量数据

    1.模拟海量数据

    存储过程/存储函数。

    create database testdata;

    use testdata;

    create table dept(

      dno int(5) primary key default 0,

      dname varchar(20) not null default ' ',

      loc varchar(30) default ' '

    ) engine=innodb default charset=utf8;

    create table emp(

      eid int(5) primary key,

    ename varchar(20) not null default ' ',

    job varchar(20) not null default ' ',

    deptno int(5) not null default 0

    )engine=innodb default charset=utf8;

    通过存储函数插入海量数据

    创建存储函数:
    (存储过程在语法上是没有return返回值的,存储函数有return。)

    产生随机数和随机字符串。(并且可以指定位数) randstring(5)  产生5位的随机字符串,模拟员工名称。

       创建存储函数  产生某一位数的随机字符串

    delimiter $

    create function randstring(n int) returns varchar(255)  

    begin

        declare all_str varchar(100) default  ' qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';

        declare  return_str varchar(255) default ' ';

        declare i int default 0;

        while i<n

        do

               set return_str = concat(return_str, substring(all_str, floor(rand()*52)+1,1));

               set i = i + 1;

        end while;

        return return_str;

    end $

    解释:

    randstring(n int) 是函数名(参数 类型) returns varchar(255) 返回值的类型和大小

    begin end是函数体,里面写逻辑

    declare 声明变量

    all_str varchar(100)  变量名 类型(大小) 默认是52个大小写字母。后面随机字符从这里面取。

    concat(参数1,参数2)  拼接字符串函数  函数赋值变量,前面加set.

          参数1:代表给谁拼接

         参数2:用什么拼接

    substring(all_str, floor(rand()*52)+1,1)  截取字符串。第一个参数是截取的字符串,第二个参数是从哪个位置截取(从1计数的),第三个参数是截取几个字符串。注意:

    rand()  产生一个[0,1)的随机数

    floor(rand()*52)+1 取下整  代表[1,52]

    return return_str;  返回值

    mysql中程序遇到;就结束了,因此要改变结束符。

            delimiter $   指定mysql的结尾符号为 $。那么中间可以用;表示存储函数的分行,而mysql也把这个存储函数当为一个整体。

    如果开启了慢查询日志,那么创建存储过程/存储函数会报错。

    解决方法:

    临时:

         show variables like '%log_bin_trust_function_creators%';

         set global log_bin_trust_function_creators=1;

    永久解决:

       my.cnf[mysqld]下加入 log_bin_trust_function_creators=1

    创建某一位数的随机数字的存储函数

    delimiter $

    create function ran_num() returns int(5)  

    begin

        declare i int default 0;

        set i = floor(rand()*100);

        return i;

    end $

    通过存储过程插入海量数据-----》利用之前的存储函数

    emp

    delimiter $

    create procedure insert_emp(in eid_start int(10), in data_times int(10))

    begin

        declare i int default 0;

        set autocommit =0;

        repeat

           insert into emp values(eid_start+i, randstring(5),  ' other', ran_num());

     set i = i + 1;

     until i = data_times

        end repeat;

        commit;

    end$

    解释:

     insert_emp(in eid_start int(10), in data_times int(10))  过程名(in 参数名1 类型1(大小), in 参数名2 类型2(大小))

    第一个参数表示的是从哪个序号开始,第二个参数表示插多少次

    set autocommit =0; 将自动提交关闭,这样不用每插入一条就提交一次;插入所有的再提交,这样速度更快

    until  repeat循环的退出条件,注意没有;结尾

    dept

    create procedure insert_dept(in dno_start int(10), in data_times int(10))

    begin

        declare i int default 0;

        set autocommit =0;

        repeat

           insert into dept values(dno_start+i, randstring(6),  randstring(8));

     set i = i + 1;

     until i = data_times

        end repeat;

        commit;

    end$

       

       真正开始插入数据:调用存储过程call

       delimiter ;

       call insert_emp(1000, 80000);

       call insert_dept(10, 30)  ;

       

       查看数据量 select count(1) from emp;

       

    2.分析海量数据profile

    方法一:profiles

    show profiles;   默认是关闭的,为空

    show variables like '%profiling%' ;

    set profiling=on;   #打开

    show profiles;  

    set profiling=on; 打开之后,才会记录之后的sql语句。

    方法二:精确分析sql诊断

    但上面不怎么精确。只能看到总共消费的时间,不能看到各个硬件消费的时间。

    精确分析sql诊断:(把profiles精确下)

    show profile all for query 上一步查询的Query_ID

    show profile cpu, block io for query 2;

    方法三:全局查询日志

    记录开启之后的全部sql语句(很费性能)(这些全局记录操作 仅仅在调优、开发过程中打开即可,在最终部署实施时一定要关闭)

    show variables like '%general_log%';

    记录到mysql自带的general_log表中

    set global general_log=1;    开启全局日志

    set global log_output =  'table ';   sql记录到表里去

    或者记录到文件中

    set global log_output ='file';

    set global general_log=1;

    set global general_log_file = '路径+文件'

    开启后,会记录sqlmysql.general_log表中

    select * from mysql.general_log;

    十、锁机制

    1.锁的分类

    解决因资源共享, 而造成的并发问题。

    分类:

    操作类型:读锁、写锁

    操作范围:表锁、行锁、页锁

    读锁:也称为共享锁,对同一个数据,多个读操作可以同时进行,互不干扰。

    写锁,也称为互斥锁,如果当前写操作没有完毕,则无法进行其他的读操作、写操作。

    表锁:一次性对一张表整体加索。如Myisam默认用表锁,特点是开销小,加索快,无死锁。但缺点是锁的范围大,容易发生锁冲突,并发度低。

    行锁:一次性对一条数据加索。如Innodb使用行锁,特点是开销大,加锁慢,容易出现死锁。锁的范围较小,不容易发生冲突,并发度高。(很小概率发生高并发问题:脏读、不可重复读、幻读)

    2.表锁

    1)表锁操作

    加锁方法:

    lock table 表名1  read/write  给表加读/写锁

    lock table 表名1  read/write, 表名2  read/write;   给多张表加读/写锁

    查看加锁的表:
        show open tables;

    释放锁:unlock tables;

    2)总结:

    (加读锁)

    如果某一会话对A表加了读锁,则该会话可以对A表进行读操作,不能进行写操作,且当前会话不能对其他表进行读写操作;对于其他会话,可以对加锁以外的其他表做任何操作(读写),对加锁的表A,只能进行读操作,写操作需要等待,直到释放锁。

    (加写锁)

    如果某一会话A表加了写锁,当前会话可以对当前表做读写操作,但是不能操作(读写)其他表。其他会话对加写锁的表A 做任何操作(读写)都会等待,直到释放锁。

    3mysql表级锁的锁模式:

    myisam在执行查询语句前,会自动给涉及的所有表加读锁,在增删改前,会自动给涉及的表加写锁。因此对myisam的表操作会出现:

    1. myisam的表进行读操作(加读锁),不会阻塞其他进程对同一表的读操作,但会阻塞同一表的写操作。只有当读锁释放后,才会执行其他进程的写操作
    2. myisam表的写操作(加写锁),会阻塞其他进程对同一表的读操作和写操作,只有当锁释放时,才会执行其他进程 的操作。

     

     

    4)分析表锁定

    查看哪些表加锁:show open tables;   1代表被加锁

    分析表锁定的严重性:show status like  'table% ';   空的?

    table_locks_immediate :即可能获取到的锁数

    table_locks_waited : 需要等待的表锁数(如果该值越大,存在越大的锁竞争)

    一般建议用二者 的比值做个权衡table_locks_immediate/table_locks_waited > 5000,采用innodb引擎,否则使用myisam引擎。(立刻能够获得资源相对比较多的时候,用行锁innodb,否则用表锁myisam

    2.行锁(innodb):

    mysql默认自动commit,为研究行锁,暂时关闭自动commit

    关闭自动提交:set autocommit=0;或者利用事务begin

    以后每写一sql语句,都要手动commit

    总结:

    如果某会话对某条数据a进行增删改操作(关闭自动commit的情况下),则其他会话必须等待那条会话事务结束后(commitrollback),才能对数据a进行操作。

    表锁通过unlock tables;来解锁,也可以通过事务来解锁,行锁通过事务解锁。

    行锁对不同数据在不同会话中间互不影响。(行锁一次锁一行数据,如果操作不同数据,互不干扰)

    行锁的注意事项:

    1. 如果没有索引,则行锁会转为表锁。(这个没有索引是从实际操作中是否有索引来说的)
    2. 行锁的一种特殊情况:间隙锁:值在范围内,却不存在。

    间隙特点:mysql会自动给间隙加锁。

    行锁:如果有where,则实际加锁的范围就是where后面的范围,不是实际的值。

     

    行锁:innodb默认采用

    优点:并发能力强,效率高

    缺点:比表锁性能损耗大(每次只锁一行,粒度小)

    建议:高并发用innodb,否则用myisam

    行锁分析:

    show status like  '%innodb_row_lock%';

      Innodb_row_lock_current_waits:当前正在等待的数量

         Innodb_row_lock_time   :等待总时长。从系统启动到现在一共等待的时间

       Innodb_row_lock_time_avg

     Innodb_row_lock_time_max

      Innodb_row_lock_waits     等待次数。从系统启动到现在一共等待的次数

     

    如果仅仅是查询数据,能否加锁?

    for updateselect语句加锁。

    select * from student where id=2 for update;    (关闭自动提交才能出效果)

     

    十一、主从复制(集群的一种方式)

    优点:负载均衡;失败迁移

    主数据库进行增删改查,再将数据同步到从数据库。读写分离,将读操作放到从数据库,将写操作放到主数据库。

    windows部署主数据库,linux部署从数据库。

    windows安装mysql(把之前安装的卸载掉):先用自带卸载工具卸载mysql;然后手动删除mysql(隐藏文件)缓存文件(没找到??);再删除注册表regeditmysql相关的。

    授权远程访问:在a计算机访问b计算机的数据库,就需要在b计算机的mysql里授权: grant all privileges on *.*  ‘root’ @’%’ identified by ‘123’ with grant option;

    flush privileges;

    如果仍保错,可能是防火墙的原因:关闭b 的防火墙:services iptables stop

    怎么实现同步(主从复制)?

    原理:同步的核心:二进制日志。所有对数据的增删改查操作都会在二进制日志文件中记录。那么这个日志文件怎么从主数据库到从数据库?从数据库一开启就有一个io线程,去读写主数据里的二进制文件,然后将写的数据放到从数据库的relay log里去。通过relay log就可以拿到二进制日志里新增或者改变的所有数据。最终sql线程将该数据放到自己从数据库里。

    原理步骤:

    (1)master将改变的数据 记录在本地的二进制文件中;该过程称之为二进制日志事件

    (2)slavemaster的二进制文件拷贝到自己的relay log(中继日志文件)里。

    (3)中继日志事件:将数据读取到自己的数据库中

    mysql要实现主从复制 是异步的, 串行化的,有延迟的。

    masterslave = 1n

  • 相关阅读:
    SqlServer事务日志满的解决方案
    关于.net反射和metadata加载致Jeffray Zhao等几位和firelong
    Context Root选/的原则
    [继续讨论]关于Windows PE和.net assembly的加载
    有趣的重写GetType()方法
    对Wintercn关于函数式编程的文章评论
    The experience to config Cisco 2811 for VOIP
    关于c#静态方法和实例方法的辨析和应用
    防止刷新时,密码输入框中的信息丢失
    计算百分比 JS
  • 原文地址:https://www.cnblogs.com/yq055783/p/12938437.html
Copyright © 2011-2022 走看看