MySQL数据库:

一)四大类语言:

mysql数据库四大类语言:DCL、DDL、DML、DQL;

1)概括:

  1. SQL语言共分为四大类:
  2. 1> 数据控制语言DCL
  3. 2> 数据定义语言DDL
  4. 3> 数据操纵语言DML
  5. 4> 数据查询语言DQL

1)数据控制语言DCL:

    数据控制语言DCL,全称:Data Control Language;
用途:    
    主要是用来 `授予`或`回收` 访问数据库的某种特权,并`控制数据库`、操纵事务发生的时间及效果,对数据库实行监视等。 

DCL包含以下语句:    
        grant : 赋予用户某种控制权限;
        revoke :取消用户某种控制权限。

2)数据定义语言DDL :

    数据定义语言DDL,全称:Data Definition Language;
用途:
    主要是用来创建数据库中的各种对象,比如:表、视图、 索引、同义词、聚簇等等; 

DDL包含以下语句:    
            create : 创建表;
            alter : 修改表的数据;
            drop : 删除表;

3)数据操纵语言DML:

    数据操纵语言DML,全称:Data Manipulation(操作) Language;

DML包含以下语句: 
            1) 插入:insert 
            2) 更新:update 
            3) 删除:delete

4)数据查询语言DQL:

    数据查询语言DQL,全称:Data Query Language;

DML包含以下语句: 
            1)SELECT


2)DCL语句:

1)概述:

        DCL,数据控制语言;        
DCL包含以下语句:    
        grant : 赋予用户某种控制权限;
        revoke :取消用户某种控制权限。

2)SQL语句-示范:

# 创建用户
    create user `zhangsan` identified by '123';
    create user `zhangsan`@`localhost` identified by '123';

# 授权
    grant all on school.* to `zhangsan`;

#撤销权限
    revoke all on school.* from `zhangsan`;

#删除用户
    drop user `zhangsan`;


3)DDL语句:

1)概述:

        DDL:数据定义语言;
DDL包含以下语句:    
            create : 创建表;
            alter : 修改表的数据;
            drop : 删除表;

2)SQL语句-示范:

# 查看当前数据库中的所有表:
                    show tables;


# 查看表的字段信息:
                desc stu;


# 在数据表原有的基础上,再增加一个hobby列(varchar(50)):
                alter table stu add hobby varchar(50);        


# 修改sname列,使其长度为60。
                alter table stu modify sname varchar(60);           

# 删除hobby列,一次只能删一列。
                alter table stu drop hobby;


#表名改为student。
                rename table stu to student;


# 修改表中的列名sname修改为username,(注意后面必须跟上数据类型):
        alter table student change sname username varchar(31);


#创建一个新表stu2
create table stu2
(
    id int not null,
    name varchar(50),
    age int,
    address varchar(100)
);


4)DML语句:

1)概述:

        DML:数据操纵语言;
DML包含以下语句: 
            1) 插入:insert 
            2) 更新:update 
            3) 删除:delete

2)SQL语句-示范:

#向表中一次添加多条数据:
    insert into stu2 values  (1,'习近平',60,'北京'),
                        (2,'李克强',62,'北京'),
                        (3,'杨洁篪',63,'北京'),
                        (4,'王岐山',64,'北京');


#修改操作:update: 
        update stu2 set address='河南' where name='李克强';


#删除一条数据:delete:
        DELETE FROM stu2 WHERE (id=4);


#删除表中所有数据:
            DELETE FROM stu2;


5)DQL语句:

1)概述:

        DQL:数据查询语言;

DML包含以下语句: 
            1)SELECT

2)SQL语句-示例:

#--- 1> 一般查询:---------------------------------- 

#查询指定列:
        select sid,age from stu;


#查询性别为女,并且年龄小于50的记录:
        select * from stu where gender='female' and age<50;


#查询学号为S_1001,或者姓名为liSi的记录
        select * from stu where sid='S_1001' or sname='LiSi';


#查询学号为S _ 1001,S _ 1002,S _ 1003的记录:
    select * from stu where sid in('s_1001','s_1002','s_1003');


#查询学号不是S_1001,S_1002,S_1003的记录:
    select * from stu where sid not in('s_1001','s_1002','s_1003');


#查询年龄为null的记录:
            SELECT * FROM stu WHERE age IS NULL;


#查询年龄在20到40之间的学生记录:
            select * from stu where age between 20 and 40;


#查询姓名不为null的学生记录:
            select * from stu where sname is not null;



#----- 2> 模糊查询:---------------------------

#查询姓名由3个字符构成的学生记录:
            select * from stu where sname like '___';


#查询姓名由5个字符构成,并且第5个字符为“i”的学生记录:
            select * from stu where sname like '____i';


#查询姓名以“z”开头的学生记录:
            select * from stu where sname like 'z%';


#查询姓名中第2个字符为“i”的学生记录:
            select * from stu where sname like '_i%';



#查询姓名中包含“a”字符的学生记录:
            select * from stu where sname like '%a%';



#--- 3> 去重:---------------------------------- 
# 去除重复记录,使用distinct:
            select distinct sal,comm from emp;



#--- 4> 排序:----------------------------------             
#升序排序:  asc
        select * from stu order by age asc;


#降序排序:  desc
        select * from stu order by age desc;


#查看表的字段信息:【与(降序排序)都是desc,注意区分】
        desc emp;


# 查询所有雇员,按 月薪sal 降序排序,
            # 如果月薪sal相同时,按 编号empno 升序排序:
        select * from emp order by sal desc,empno asc;



#--- 5> 聚合函数:---------------------------------- 
#---- count();  max();  min(); sum();  avg();  

# 查询emp表中记录数:
        select count(*) as '记录数' from emp;


#查询emp表中,有佣金comm 的人数:
        select count(comm) as '有佣金的人数' from emp;


#查询有佣金的人数,以及有领导的人数:
        select count(comm) as '有佣金的人数',count(mgr) as '有领导的人数' from emp;


#查询所有雇员月薪和,以及所有雇员佣金和:
        select sum(sal),sum(comm) from emp;


#统计所有员工平均工资:
        select avg(sal) as '所有员工平均工资' from emp;


#查询最高工资和最低工资:
        select max(sal) as '最高工资',min(sal) as '最低工资' from emp;



#--- 6> 分组查询:----------------------------------

#查询每个部门的 部门编号deptno 和每个部门的 工资sal 和:
    -- 意思就是,查询部门编号deptno,工资sal 和,每个部门的意思就是——以部门进行分组;
        select deptno,sum(sal) from emp group by deptno;  


# 查询每个部门的部门编号以及每个部门的人数:
        select deptno,count(*) from emp group by deptno;  


#查询每个部门的部门编号以及每个部门工资大于1500的人数:
        select deptno,count(*) from emp where sal>1500 group by deptno;  



#--- 7> having子句:---------------------------------- 
# 查询 部门工资总和大于9000的部门编号以及工资和:
        select deptno,sum(sal) from emp group by deptno having sum(sal)>9000;



#--- 8> LIMIT分页:----------------------------------
# 查询第1条到第10条的数据的sql是:
        select * from table limit 0,10;

3)having、where、group by 的区别与联系:

1. having是在分组(group by)后,对数据进行过滤;

2. where是在分组(group by)前,对数据进行过滤;

3. having后面,可以使用分组函数(sum、max、min、avg、count这些…);

4. where后面不可以使用分组函数;

5. where的优先级 高于 分组(group by) 高于 having;
      即,where是在分组前对数据进行过滤,如果某行数据没有满足WHERE子句的条件,那么这行记录根本就没资格参加分组;
      而 having,则是在分组(group by)后,对数据的再次过滤。

4)查询语句—书写顺序 :

查询语句书写顺序:
    select 字段名 from 表名 where `条件过滤` group by `用什么来分组` having `分组后再次过滤` order by `根据什么来排序` limit 0,10;

5)查询语句—执行顺序:

查询语句执行顺序:
    from 表 
        -where 
            -group by 
                -having 
                    - select 
                        - order by
                                -limit

二)数据完整性约束:

1)定义:

    **数据完整性是指,数据的正确性和相容性,是为了防止数据库中存在不符合SQL语义的数据,即防止数据库中存在不正确的数据。**

    **在MySQL中提供了多种完整性约束。**

2)数据完整性约束的分类:

数据完整性约束主要分为3类:
                - 实体完整性 约束:
                - 域完整性 约束:
                - 引用完整性 约束:

3)实体完整性约束:

3.1)概述-分类:
1> 主键约束:primary key,保证数据的唯一性,数据不能重复,不能为null;

2> 唯一约束:unique key,数据不能重复,可以为null;

3> 自动增长约束:auto_increment;

3.2)自动增长约束 详述:
    自动增长:auto_increment,自动增长约束不能单独使用,一般用于和主键配合。给主键添加自动增长的数值;

1> 什么时候触发自动增长:
        给定属性的字段没有提供值 的情况下。

2> 自动增长的适用场景:    
        自动增长只适用于数值类型的列,
        而且,自动增长的列必须是个key,主键外键唯一键都行,
        且一张表只有能有一个自增长的 列;

3> 自动增长的基本语法:        
        在字段之后增加一个属性auto_increment ;    
    eg:
         create table stu{
             id int primary key auto_increment,
             name varchar(10),
             pwd varchar(16)
         }

4> 自动增长的初始设置:    
        在系统中,有一组变量用来维护自增长的初始值和增量;
        auto_increment_increment 表示:增量,
        auto_increment_offset 表示:初始值

4)域完整性约束:

    域完整性约束的作用:限制此单元格中的数据,该约束不会对其它单元格起作用,域代表——当前单元格。

域完整性约束-分类:
            1> 数据类型约束、
            2> 非空约束(not null) 
            3> 默认值约束(default)  
            4> check约束(mysql不支持)check(sex='男'or  sex='女')

5)引用完整性约束:

    外键约束:foreign key

eg:添加外键:
#学生表(主表)
CREATE TABLE student(
      sid int primary key,
       name varchar(50) not null,
      sex varchar(10) default '男'
);

#成绩表(从表)
create table score(
      id int,
      score int,
      sid int , 
      constraint foreign key(sid) references student(sid)
);

-- PS:外键的字段的数据类型一定要与主键的类型一致;

四)数据库事务

1)事务的四大特性:

数据库中事务的四大特性(ACID):

原子性    一致性      隔离性      持久性

⑴ 原子性(Atomicity)

    原子性是指事务包含的所有操作要么全部成功,要么全部失败,执行回滚操作。

⑵ 一致性(Consistency)

    一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

    拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

⑶ 隔离性(Isolation)

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

⑷ 持久性(Durability)

持久性是指一个事务一旦被commit提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

2)事务的隔离级别:

什么是事务的隔离性:

     事务的隔离性,当多个线程都开启事务来操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据时的准确性。

四种隔离级别:

                    **读未提交**  ----  最低级别,(会出现脏读, 不可重复读),基本不使用

                    **读已提交**  ----  (可以处理脏读的问题,但会出现不可重复读和幻读) (Oracle默认)

                    **可重复读**  ----  (可以处理脏读、不可重复读的问题,但会出现幻读)(mysql默认)

                    **序列化读**  ----  最高的事务隔离级别,效率低。

3)事务并发的问题:

            **答:脏读、不可重复读、幻读;**

1> 脏读:
    一个事务中,读到了其他事务**还没有提交**的数据;

2> 不可重复读:
    举例:事务A首先读取了一条数据,然后在执行其他一些逻辑的时候,事务B突然将这条数据给改变了,然后当事务A**再次读取该数据的时候**,**发现前后数据的值不一致了,就是所谓的不可重复读**。

    即,一个事务先读取了一次数据,而之后再次读取该数据时,该数据的值却是别的事务已经修改后的新值,**导致前后两次读取到的数据值不一致,这就是不可重复读**。

3> 幻读:
    举例一:事务A首先**根据条件读取到N条数据**,然后事务B又悄悄的增添了M条符合事务A读取条件的数据,导致事务A再次根据条件读取数据时,读到了N+M条数据,**导致前后读取到的数据的数量不一致,这就是幻读**。

    举例二:再就是,事务A第一次根据条件搜索的时候**没有查到某数据**,**但是在第二次操作时,却查到了该数据,这就是幻读**。

4)事务的隔离级别:

1)读未提交 :
    读未提交,顾名思义,就是一个事务**可以读取到另一个事务未提交**的数据。

    这是最低的隔离级别,**会导致“脏读”、“幻读”和“不可重复读取”**。

2) 读已提交:
    读已提交,顾名思义,就是**一个事务必须要等到另一个事务提交对该数据的操作**以后,才能读取该数据。

    这个隔离级别,**避免了“脏读取”**;不能避免“不可重复读取”和“幻读”。

    这是**Oracle数据库采用的默认事务级别**。

3)可重复读 :
    可重复读,就是**在一个事务开始读取数据时,不再允许其他的事务对该数据的值进行任何的修改操作;**

    **这样当该事务再一次读取该数据的时候,前后的数据的值是一样的**;

    避免了“脏读取”和“不可重复读取”的事务并发问题,**不能避免“幻读”**。

    这是**mysql数据库采用的默认事务级别**。

4)序列化读:
    最严格的级别,**事务串行化按顺序执行**;

    可以避免脏读、不可重复读与幻读。

    但是这种事务隔离级别,比较耗费系统性能,一般不使用。

五)SQL语句专题

详情见:

https://blog.csdn.net/qq_44750696/article/details/124089092

六)数据库索引

一,索引的概念

1,什么是索引:

    在数据库中,索引的含义与日常意义上的“索引”一词并无多大区别,与书中的索引一样,数据库中的索引使您可以**快速**找到表中的特定信息。

    索引包含从表中一个或多个列生成的键,以及映射到指定数据的存储位置的指针,也就是说**索引由 键 和 指针组成。**

    索引可以大大提高数据库的检索速度。

2,建立索引的好处:

2.1)索引可以避免全表扫描
    带索引的查询可以仅扫描少量索引页及数据页,而不是遍历所有数据页即全盘扫描,加快找到目标数据的速度。

2.2)索引还可用于避免排序操作
    一些情况下,索引还可用于避免排序操作。**索引本身就是排序**。比如说读需要有顺序的数据,会直接读索引,再通过索引,找到数据。

    一个索引只能对每个索引列支持一种排序规则。尽量利用索引排序,即取出的数据就是有序的。

3,建立过多的索引的坏处:

    索引需要付出的代价和带来的弊端:

1,增加了数据库的存储空间 ;
    建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但是如果你在一个数据量比较大的表上创建了多种组合索引,那么索引文件的增长会很快,这就显著增加了数据库的存储压力。

2,增加了插入和修改数据时的复杂度;
    在插入和修改数据时要花费较多的时间(因为索引也要随之变动);

    虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行insert、update和delete。因为更新表时,不仅要保存数据,还要保存一下索引文件。

3,如果索引建立不当,反而可能会削弱查询速度;
    对某些数据量不是很大的表,对于某些添加索引的行为,不但不能优化查询速度,反而会减慢查询速度,当然,如果索引的建立不恰当,所选择建立索引的字段不合适,也可能会削弱查询速度。

4,索引的目的:

    索引的目的在于提高查询效率,可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。

    如果没有索引,那么你可能需要把所有单词查找一遍才能找到你想要的。

二,索引的数据结构

    任何一种数据结构都不是凭空产生的,一定会有它的背景和使用场景。

    我们需要索引这种数据结构能够做些什么?其实很简单,那就是:**使用索引,将每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级**。

    那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢?就这样,b+树应运而生。

1,页

    数据库文件存储是以页为存储单元的,一个页是8K(8192Byte),一个页就可以存放N行数据。

    我们常用的页类型就是`数据页`和`索引页`。

    一个页中除了存放基本数据之外还需要存放一些其他的数据,如页的信息、偏移量等。

2,磁盘IO与预读

    考虑到磁盘IO是非常高昂的操作,计算机操作系统做了一些优化,当一次IO时,不光把当前磁盘地址的数据,**而是把相邻的数据也都读取到内存缓冲区内**,

    因为局部预读性原理告诉我们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。

    **每一次IO读取的数据我们称之为一页(page),页是数据库文件存储的存储单元**。

3,铺垫,什么是B树:

    B树中要求所有的叶节点都在同一层;

    2-3树是B树中的一项特例。2-3树分为两种,一种是2节点,一种是3节点。有两个子节点的节点叫二节点,有三个子节点的节点叫三节点。

    比如说像这种节点,有三个子节点,就是三节点;

数据库知识总结 - 图1

    像6这种节点,只有两个子节点,就是二节点。

数据库知识总结 - 图2

    二节点要么有两个子节点,要么没有子节点;

    三节点要么有三个子节点,要么没有子节点。

    (同理,四节点就是要么有四个子节点,要么没有子节点。)

    2-3树、2-3-4树这些其实都是B树,只不过都是B树的一种特例。
   **什么是B树呢**,其实就是2-3树、2-3-4树、2-3-4-5树...等等等等,将这些统称为B树。

  **在B树中,最大的节点的数字,称之为该B树的阶**。比如说2-3树是3阶的B树、2-3-4树就是4阶的B树;

4,什么是B+树?

    B+树是B树的一种变形。它相比于B树主要有两个变化。

1,非叶子结点只存储索引信息,不存储数据;

比如说这颗B+树,真正的数据只存储于它的叶子结点中,它的所有的非叶子结点只存储索引信息、只是用来帮助找到相应的数据用的。

数据库知识总结 - 图3

2, 每一个叶子节点最右边的指针,指向下一个相邻的叶子结点。
    比如说0001这个节点指向它右边的那个节点——0002、0003、0003;

    0002、0003、0003这个节点指向它右边的那个节点——0004、0005;

    ......

    也就是说, 所有的叶子结点组成了一个有序链表 。

数据库知识总结 - 图4

5,B+树的优点:

    当真正的数据存储在硬盘中的时候,当将B+树中所有的**非叶子结点的信息也就是索引的信息都存储到内存中**以后,

    当我们想要找某一条数据的时候,**只需要通过一次硬盘IO就可以读取到相应的数据了**。

    **就是说我们将更多的索引信息存储到内存中以后,我们就可以通过索引去快速的找到相应的数据**。

    如果是普通的B树的话,可能就需要去一次一次的读取数据和对比数据了。

    而在实际情境下很可能的情况是**数据量非常大、索引量很小**,所以我们就可以采用B+树的数据结构,将索引信息都存储在非叶子结点中,将数据都存储在叶子节点中,这样就可以快速的去找到相应的数据了。

    当然B+树和B树各有优缺点,各自适用于不同的实际场景中。

6,b+树的查找过程

数据库知识总结 - 图5

    比如说,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,

    通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,

    29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。

    **真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的**,

    如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。

详解b+树参见:

https://blog.csdn.net/qq_44750696/article/details/123610382

三,MySQL有哪几种索引

MySQL目前主要有以下几种索引类型:

  1. 普通索引
  2. 唯一索引
  3. 主键索引
  4. 组合索引
  5. 全文索引

1、普通索引

    普通索引是最基本的索引,它没有任何限制。功能就是加速查找。

    普通索引有以下几种创建方式:

1)直接创建索引
CREATE INDEX index_name ON table_name (column_name)

举例:

创建一个简单的索引,名为 “PersonIndex”,在 Person 表的 LastName 列:

CREATE INDEX PersonIndex ON Person (LastName)

如果希望以降序 索引某个列中的值,您可以在列名称之后添加保留字 DESC

CREATE INDEX PersonIndex ON Person (LastName DESC)

假如希望该索引不止一个列,是一个组合索引,可以在括号中列出这些列的名称,用逗号隔开:

CREATE INDEX PersonIndex ON Person (LastName, FirstName)

2)在已有表的基础上追加索引:
ALTER table table_name ADD INDEX index_name(column_name)
ALTER table table_name ADD INDEX index_name(column_name(length))

3)创建表的时候同时创建索引
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    INDEX index_name (title(length))
)

4)删除索引
DROP INDEX index_name ON table_name

2、唯一索引

    与前面的普通索引类似,唯一索引不同的就是:索引列的值必须唯一,但允许有空值。

    即,相比于普通索引,唯一索引,还多了一个**唯一性约束**的功能。

    如果是组合索引,则列值的组合必须唯一。

1)创建唯一索引
CREATE UNIQUE INDEX index_name on table_name(column_name);
CREATE UNIQUE INDEX index_name ON table_name(column_name(length))

2)修改表结构
ALTER TABLE table_name ADD UNIQUE index_name (column_name)
ALTER TABLE table_name ADD UNIQUE index_name (column_name(length))

3)创建表的时候直接指定
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    UNIQUE indexName (title(length))
)

3、主键索引

    主键索引是一种特殊的唯一索引,**一般情况下也是表中默认的聚簇索引**;

    一个表只能有一个主键;建立主键索引的列,**首先也具备唯一索引的性质,具有唯一性约束;除此之外还不允许有空值**。

    一般是在建表的时候同时创建主键索引:
CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
     PRIMARY KEY (`id`)
)

4、组合索引

    组合索引是指在多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。

    使用组合索引时遵循最左前缀集合:
CREATE INDEX index_name on table_name (column1, column2);
ALTER TABLE table_name ADD INDEX index_name (column1,column2,column3);

5、全文索引

    全文索引主要用来查找文本中的关键字,而不是直接与索引中的值相比较。

    fulltext全文索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。

    fulltext索引配合match against操作使用,而不是一般的where语句加like。

(1)创建表的适合添加全文索引

CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) CHARACTER NOT NULL ,
    `content` text CHARACTER NULL ,
    `time` int(10) NULL DEFAULT NULL ,
    PRIMARY KEY (`id`),
    FULLTEXT (content)
);

(2)修改表结构添加全文索引

ALTER TABLE table_name ADD FULLTEXT index_name(content)

(3)直接创建索引

CREATE FULLTEXT INDEX index_name ON table_name(content)

四,建立和使用索引的几个原则:

    使用索引时,有以下一些技巧和注意事项:

1、满足最左前缀匹配原则:

    WHERE可后接多个条件。一般地,**执行引擎可以优化WHERE后多个条件的查询顺序**。

    非常重要的原则,mysql会一直向右匹配,**直到遇到范围查询(>、<、between、like)就停止匹配**,

    比如:

    `a = 1 and b = 2 and c > 3 and d = 4`

    如果建立(a,b,c,d)顺序的索引,**d是用不到索引的**。

2、尽量选择区分度高的列作为索引:

    区分度表示:字段的数据不重复的比例;

    字段内的数据不重复的比例越大,我们查询数据的效率越高;

3、尽量使用数据量小的、经常用作查询条件的列作为索引

4、不要在索引列上进行计算:

    索引列不能参与计算,保持列“干净”,不要在列上进行运算,**否则将导致索引失效而进行全表扫描**。

    比如`from_unixtime(create_time) = ’2014-05-29’`就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,**需要先把所有元素都应用到函数中之后才能比较,显然成本太大**。

    所以语句应该写成`create_time = unix_timestamp(’2014-05-29’)`。

5、 尽量的扩展索引,不要新建索引。

    比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可,不用新建索引。

6、不要设置过多的索引,合理应用组合索引

    不要设置过多的索引,过多的索引首先会带来更大的磁盘空间,而且在数据发生修改时,对索引的维护是特别消耗性能的。

    如果需要,**最好给这些列建立为一个组合索引**。

7、尽量使用索引排序

    因为**索引本身也是有序的**,合理的SQL可以**利用索引避免和减少排序**,是一个不错的方法。

    **如果在需要排序的字段上面建立了合适的索引,那么就可以跳过排序的过程,提高SQL的查询速度**。

    对于不能利用索引避免排序的SQL,则才考虑使用数据库自己实现排序功能以满足用户需求。

    详情见:[https://blog.csdn.net/qq_44750696/article/details/123638577](https://blog.csdn.net/qq_44750696/article/details/123638577)

8、like语句,%百分号不能放首位

    一般情况下不推荐使用like操作模糊查询,如果非使用不可,如何使用也是一个技巧:
  • like “%aaa%” 不会使用索引;
  • 而like “aaa%”可以使用索引。

9、不使用not in操作,谨慎使用in操作

    NOT IN 是强列推荐不使用的,因为它不能使用表的索引,会导致数据库放弃索引、进行全表扫描。推荐用NOT EXISTS 或(外连接+判断为空)方案代替。

    关于in操作的使用也要谨慎,**如果是确定且有限的集合时,可以使用,如 IN (0,1,2)**。否则如果集合比较大的话,查询效率会很低,而且查询结果容易有误。

10、谨慎使用 or :

    使用了 or 条件的字段们,只要有一个不是索引列,就会导致索引失效,数据库进行全表扫描。
    select * from tb1 where nid = 1 or name = 'seven@live.com';  -- nid 和 name 字段如果有一个不是索引,就会导致索引失效。

注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引;

    **建议使用 union来替代or ,拼接多个查询语句。**

11、普通索引中,使用!=不等于不会走索引

    select * from tb1 where email != 'alex'
    注意:**如果是主键,则还是会走索引**,比如:`select * from tb1 where nid != 123`<br />

五,什么是聚簇索引

1,聚簇索引的概念:

    **MySQL 里只有 INNODB 表支持聚集索引**。

    聚簇索引不是一种索引类型,而是一种数据存储方式。innoDB的**聚簇索引实际上在同一个结构中保存了索引和数据行**。

    当表有聚簇索引时,它的行数据实际上存放在索引的叶子页中,因为无法同时把数据行存放在两个不同的地方,**所以一个表只能有一个聚簇索引**。

    当创建表时创建了主键,MySQL会自动创建名为**PRIMARY**的特殊索引--主键索引, **该索引称为聚簇索引**。

    **PRIMARY主键索引是比较特殊的,**这个**索引本身与数据一起存储在同一个表中**。

    如果表没有聚集索引,则其数据行存储在一个称为堆的无序结构中。InnoDB**对主键建立聚簇索引**,如果你不指定主键,InnoDB会用一个具有唯一且非空值的索引来代替。

    除**PRIMARY**主键索引/聚簇索引之外的其他索引,**称为二级索引或非聚簇索引**。

2,InnoDB的聚簇索引:

  • 聚簇索引(primary索引):主键索引

  • 什么是二级索引:叶子节点保存的不是指行的物理位置的指针,而是行的主键值。

    非聚簇索引(second索引):二级索引