1.索引
2.函数
3.存储过程
4.视图
5.触发器

1.索引
    在数据库中索引最核心的作用是:加速查找。:例如:在含300万条数据的表中查询,无索引需要700秒,而利用索引可能仅需1秒
    1.1索引原理
        为什么加上索引后速度能有这么大的提升呢?
        因为索引的底层是基于B+Tree的数据结构存储的
        数据库的索引是基于上述B+Tree的数据结构实现,但在创建数据库表时,如果指定不同的引擎,底层使用的B+Tree结构的原理有些不同
            myisam引擎,非聚簇索引(数据和索引结构分开存储)
            innodb引擎,聚簇索引(数据和主键索引结构存储到一起)
        1.1.1非聚簇索引(myisam引擎)

create table 表名(
                 in int not null auto_increment primary key,
                 name varchar(32) not null,
                 age int
             )engine=myisam default charset=utf8;


        1.1.2聚簇索引

create table 表名(
                 in int not null auto_increment primary key,
                 name varchar(32) not null,
                 age int
             )engine=innodb default charset=utf8;


    一般使用innodb引擎,聚簇索引
    1.2常见索引
        在innodb引擎下,索引底层等都是基于B+Tree的数据结构存储的(聚簇索引)
            主键索引:加速查找,不能为空,不能重复。+联合主键索引
            唯一索引:加速查找,不能重复。+联合唯一索引
            普通索引:加速查找。+联合索引
        1.2.1
            主键和联合主键索引

create table 表名(
                     id int not null auto_increment primary key,    --主键
                     name varchar(32) null
                 );
                 create table 表名(
                     id int not null auto_increment,
                     name varchar(32) not null,
                     primary key(id)
                 );
                 create table 表名(
                     id int not null auto_increment,
                     name varchar(32) not null,
                     primary key(列1,列2)
                 );                                    --如果有多列,称为联合主键(不常用且myisam引擎支持)


            
                如果表结构已经创建完成:
                    alter table 表名 add primary key(列名);
                    alter table 表名 drop primary key;
                注意:删除索引是时可能会报错,自增列必须定义为键。
                    如果删除键,必须连带把那列的自增取消:alter table 表 change id int not null;
            唯一和联合唯一索引
          

create table 表名(
                     id int not null auto_increment primary key,
                     name varchar(32) not null,
                     email varchar(64) not null,
                     unique ix_name(name),
                     unique ix_email(email)                    --两个单列的唯一索引
                 );
                 reate table 表名(
                     id int not null auto_increment primary key,
                     name varchar(32) not null,
                     email varchar(64) not null,
                     unique (列1,列2)                        --如果有多列称为联合唯一索引
                 );
                 
                 create unique index 索引名 on 表名(列名);
                 drop unique index 索引名 on 表名;


            
            
            1.2.3索引和联合索引
          

create table 表名(
                     id int not null auto_increment primary key,
                     name varchar(32) not null,
                     email varchar(64) not null,
                     index ix_name(name)
                 );
                 create table 表名(
                     id int not null auto_increment primary key,
                     name varchar(32) not null,
                     email varchar(64) not null,
                     index  ix_email_name(列1,列2)                        --如果有多列称为联合索引
                 );
                 
                 create index 索引名 on 表名(列名);
                 drop index 索引名 on 表名;


    1.3操作表————查询是要命中索引呀
        一般情况下,我们针对只要通过索引去搜搜都可以命中索引(通过索引结构加速查找)
        特殊情况下,让我们无法命中索引(即使创建了索引),这也是大家在开发中需要注意的:
            类型不一致:
                select * from big where name=123;   --未命中
                select * from big where email=123;  --未命中
                特殊的主键:
                    select * from big where id='123';
            使用不等于:
                select * from big where name!="wupeiqi";        --未命中
                select * from big where email!="111@qq.com"        --未命中
                特殊的主键:
                    select * from big where id!=123             --命中
            or,当or条件中有为建立索引的列才失效
                select *from big where id=123 or password='xx';        --未命中
                特别的:
                    select * from big where id=10 or password='xx' and name='xx';        --命中
            排序,当根据索引排序时候,选择的映射如果不是索引,则不走索引
                select * from big order by name asc;        --未命中
                特殊的:
                    select name from big order by name asc;        --命中
                特别的主键:
                    select * from big order by id desc;
            like,模糊匹配时
                select * from big where name like "%u-12-19999";    --未命中
                select * from big where name like "_u-12-19999";    --未命中
                select * from big where name like "wu-%-19999";    --未命中
                特别的:
                    select * from big where name like "u-12-19999%";    --命中,通配符在最后
                    select * from big where name like "u-%";            --命中,通配符在最后
            使用函数:
                select *from big where reverse(name)="wupeiqi";        --未命中
                特别的:
                select *from big where name=reverse("wupeiqi");        --命中,函数在最后
            最左前缀,如果是联合索引,要遵循最左前缀原则:
                如果联合索引为:(name,password):
                    name and password    --命中
                    name                --命中
                    password            --未命中
                    name or password    --未命中
        常见的无法命中索引的情况就是上述示例。

1.4执行计划
    MySQL中提供了执行计划,让你能够预判SQL的执行(只能给到一定的参考,不一定完全能预判准确)
    explain+sql语句
    其中比较重要的是type,它是SQL性能比较重要的标志,性能从低到高依次是

all     <         index         <         range         <         index_merge <ref_or_null<    ref            <    eq_ref    <    system        /        const


        全盘扫描    全索引扫描            对索引范围扫描            索引合并                索引查找             连表操作    系统表仅有一行/(根据主键/唯一索引且结果只有一行)
小结:
    根据情况创建合适的索引(加速查找)
    有索引,则查询时要命中索引。
2.函数
    2.1常用函数

selelct count(id),max(id),min(id),avg(id) from d1;


                个数      最大值  最小值  平均值    
  

reverse(name)反转
         concat(name,name)字符串拼接
         now()时间
         date_format(now(),"%Y-%m-%d %H:%i:%s")格式化时间
     
         select concat('alex','sb')
         select sleep(1)等两秒钟
         char_length(str)
         concat_ws(separator,str1,str2,...)
             字符串拼接(自定义连接符)
             concat_ws()不会忽略任何空字符串。(然而会忽略所有的NULL)。
         conv(N,from_base,to_base)


            进制装换
                例如:
                    select conv('a',16,2);表示将a由16进制转换为2进制字符串表示
    2.2创建函数

delimiter $$
         create function f1(
             i1 int,
             i2 int)
         return int
         begin
             declare num int;
             declare maxid int;
             select max(id) from big into maxid;
             set num=i1+i2+maxid;
             return(num)
         end $$
         delimiter ;
         执行函数
             select f1(11,22);
             select f1(11,id),name from d1;
         删除函数
             drop function fi;


        
        delimiter $$将默认的终止符换成$$
3.存储过程
    存储过程,是一个存储在MySQL中的sql语句集合,当主动去调用内存时,其中内部的SQL语句会按照逻辑执行。
        创建存储过程
 

delimiter $$
         create procedure p1()
         begin
             select * from d1;
         end $$
         delimiter ;
     执行存储过程
         call p1();
     删除存储过程:
         drop procedure p1;


        
        
    3.1参数类型
        存储过程的参数可以有如下三种:
            in,仅用于传入参数用

out,仅用于返回值用
             inout,既可以传入又可以当做返回值
         delimiter $$
         create procedure p2(
             in i1 int,
             in i2 int,
             inout i3 int,
             out r1 int
         )
         begin
             declare temp1 int;
             declare temp2 int default 0;
             set temp1=1;
             set r1=i1+i2+temp1+temp2;
             set i3=i3+100;
         end $$
         delimiter ;
         
         
         set @t1=4;
         set @t2=0;
         call p2(1,2,@t1,@t2);
         select @t1,@t2;


        
    3.2返回值&结果集
    3.3事物和异常
        事物,成功都成功,失败都失败

delimiter $$
         create procedure p4(
             out p_return_code tinyint
         )
         begin
             declare exit handler for sqlexception
             begin
                 --error
                 set p_return_code=1;
                 rollback;        
             end;
         
             declare exit handler for sqlwarning
             begin
                 --warning
                 set p_return_code=2;
                 rollback;        --回滚,删除的数据在恢复过来
             end;
         
             start transaction;    --开启事物
                 delete from d1'
                 insert into tb(name)values('seven');
             commit;--提交事务
         
             --success
             set p_return_code=0;
         
             end $$
         delimiter ;
         
         set @ret=100;
         call p4(@ret);
         select @ret;


    
    3.4游标(效率比较低)

delimiter $$
         create procedure p5()
         begin
             declare sid int;
             declare sname varchar(50);
             declare done int default false;
             
             
             declare my_cursor cursor for select id,name from d1;
             
             declare continue handler for not found set done=True;
             
             open my_cursor;
                 xxoo:loop
                     ferch my_cursor into sid,sname;
                     if done then
                         leave xxoo;
                     end if;
                     insert into t1(name) values(sname);
                 end loop xxoo;
             close my_cursor;
         end $$
         delimiter ;
         call p5();


        
4.视图
    视图其实是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当做表来使用。
    子查询
  

select 
             *
         from
             (select nid,name from tb1 where nid>2) as A
         where
             A.name>"alex"


    创建视图
    

create view v1 as select id,name from d1 where id>1;


    使用视图
    

select *from va;


    删除视图
      

drop view v1;


    修改视图
  

alter view v1 as Sql语句


    注意:基于视图只能查询,针对视图不能执行增加,修改,删除。如果原表发生变化,视图表也会发生变化
5.触发器
    对某个表进行【增删改】操作的前后如果希望触发某个特定的行为时,可以使用触发器

#插入前
     create trigger tri_before_insert_tb1 before insert on tb1 for each row
     begin
         ...
     end
     
     #插入后
     create trigger tri_after_insert_tb1 after insert on tb1 for each row
     begin
         ...


    end
    删除
    更新
    ...
    
    示例:
        在T1表中插入数据之前,先在T2表中插入一行数据。

delimiter $$
             create trigger tri_before_insert_tb1 before insert on t1 for each row
             begin
             
             if new.name='alex' then
                 insert into t2(name) values(new.id);
             end if;
             
             end $$
             delimiter ;
             
             insert into t1(id,name,email) values(1,'alex','111@qq.com')


        在t1表中删除数据之后,再在t2 表中插入一行数据。

delimiter $$
             create trigger tri_after_insert_tb1 after delete on t1 for each row
             begin
             
             if new.name='alex' then
                 insert into t2(name) values(old.id);
             end if;
     
             end $$
             delimiter ;


        特别的:new表示新数据,old表示原来的数据