MySQL知识点整理

索引

为何要有索引?

索引的功能就是加速查找

一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重。说起加速查询,就不得不提到索引了。

什么是索引?

索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。

B+Tree

B+树是一个平衡的多叉树。

InnoDB存储引擎就是用B+Tree实现其索引结构。

在B+Tree中,所有的数据都是存放在叶子节点上的,并且是按照键值大小顺序存放的,而非叶子节点上只存储键值信息,这样可以有效的加大每个节点存储的键值数量,从而降低B+Tree的高度。

数据库中的B+树索引可以分为聚集索引(clustered index)和辅助索引(secondary index)

相同点:

其内部都是B+树的形式,即高度是平衡的,叶子结点存放着所有的数据。

不同点:

聚集索引叶子结点存放的是整张表的行记录数据

辅助索引的叶子节点不包含行记录的全部数据。

MySQL常用索引

普通索引INDEX:加速查找

唯一索引:
    -主键索引 PRIMARY KEY:加速查找+约束(不为空、不能重复)
    -唯一索引 UNIQUE:加速查找+约束(不能重复)

联合索引:
    -PRIMARY KEY(id,name):联合主键索引
    -UNIQUE(id,name):联合唯一索引
    -INDEX(id,name):联合普通索引

创建/删除索引的语法 

#方法一:创建表时
      CREATE TABLE 表名 (
                字段名1  数据类型 [完整性约束条件…],
                字段名2  数据类型 [完整性约束条件…],
                [UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
                [索引名]  (字段名[(长度)]  [ASC |DESC]) 
                );


#方法二:CREATE在已存在的表上创建索引
        CREATE  [UNIQUE | FULLTEXT | SPATIAL ]  INDEX  索引名 
                     ON 表名 (字段名[(长度)]  [ASC |DESC]) ;


#方法三:ALTER TABLE在已存在的表上创建索引
        ALTER TABLE 表名 ADD  [UNIQUE | FULLTEXT | SPATIAL ] INDEX
                             索引名 (字段名[(长度)]  [ASC |DESC]) ;
                             
#删除索引:DROP INDEX 索引名 ON 表名字;

删除主键索引

如果一个主键是自增长的,不能直接删除该列的主键索引,应当先取消自增长,再删除主键索引。

alter table 表名 drop primary key; 
 

当主键为自增长时
alter table t1 modify id int ; 【重新定义列类型】
alter table t1 drop primary key;

 

正确使用索引

1、应该选择区分度高的字段作为索引字段
2、范围问题(:>、>=、<、<=、!= 、between...and...、like、),范围过大,即便是有索引速度也会很慢
3、索引字段一定不能参与计算:select * from s1 where salary*12 > 200000;
4、最左前缀匹配原则:
  应该把范围查询字段往右放

  联合索引的第一个字段必须出现在查询条件中,顺序无所谓,否则无法命中索引。换句话说只要联合索引的第一个字段出现在查询条件中,即可命中索引。

注意事项

- 避免使用select *
- 使用count(1)或count(列) 代替 count(*)
- 创建表时尽量使用 char 代替 varchar
- 表的字段顺序,固定长度的字段优先
- 组合索引代替多个单列索引(经常使用多个条件查询时)
- 尽量使用短索引
- 使用连接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致 (select name from user where email=66666

 视图

视图(View)是一种虚拟存在的表,对于使用视图的用户来说基本上是透明的。视图并不在数据库中实际存在,行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的。

使用视图我们就可以将一些复杂的查询结果存到了一张临时表中,以后我们再次使用这些数据时,不用进行复杂的查询,直接使用视图就行。

但视图有明显地效率问题,并且视图是存放在数据库中的,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,也就意味着扩展sql极为不便,因此并不推荐使用。

创建视图或修改视图。

创建视图需要有 create view的权限,并且对于查询涉及的列有 SELECT 权限。如果使用create or replace或者alter 修改视图,那么还需要该视图的 drop 权限。

语法:create view 视图名称 as SQL语句
create view teacher_view as select tid from teacher where tname='李平老师';

#于是查询李平老师教授的课程名的sql可以改写为
select course_name from course where teacher_id = (select tid from teacher_view);
创建视图
语法:alter view 视图名称 as SQL语句
alter view course_view as select * from course where cid>3;

注意:MySQL 视图的定义有一些限制,例如,在 FROM 关键字后面不能包含子查询,这和其他数据库是不同的,如果视图是从其他数据库迁移过来的,那么可能需要因此做一些改动,可以将子查询的内容先定义成一个视图,然后对该视图再创建视图就可以实现类似的功能了。

删除视图

语法:drop view 视图名称

drop view teacher_view

查看视图

从 MySQL 5.1 版本开始,使用 show tables 命令的时候不仅显示表的名字,同时也会显示视图的名字,而不存在单独显示视图的 show views 命令。

触发器

触发器有点类似于Python中的装饰器,他是为了在对表进行【增、删、改】操作之前或之后执行一些指定的操作。当然我么也可以在触发器被触发时进行判断,然后再决定是否执行指定的操作。

触发器的功能通过Python也可以实现,只不过触发器是MySQL提供给我们的一个功能。但是如果使用了触发器我们就不能在程序级别控制。最好不要使用。

创建触发器

语法:
create trigger trigger_name trigger_time trigger_event
       on table_name for each row trigger_stmt

 trigger_name: 触发器的名称。

trigger_time: 触发器的触发时间。可以是before(之前触发)或者after(之后触发)。

trigger_event: 触发器的触发事件。可以是insert、update或者delete。

create trigger auto_add_svip after insert on user for each row
# 当我们向user表中插入一条记录后激活名为auto_add_svip触发器。

使用触发器

create table user (
  id int auto_increment primary key,
  name char(16),
  type enum('VIP', 'SVIP') default 'VIP'
);


create table SVIP(
  id int auto_increment primary key,
  name char(16)
);

delimiter $$  # 重新指定SQL语句的执行标志
create trigger auto_add_svip after insert on user for each row

begin
  if new.type = 'SVIP' then
    insert into SVIP(name) values(new.name);  #必须加分号
  end if ;  #必须加分号

end $$
delimiter ;  # 重新指定SQL语句的执行标志

drop trigger auto_add_svip;


insert into user(name,type) values
  ('jun', 'SVIP');  # 当向user表中插入类型为SVIP数据后,会激活触发器。向SVIP表中插入一条指定的数据。
触发器示例

注意:NEW表示即将插入的数据行,OLD表示即将删除的数据行。

查看触发器s

可以通过执行 show triggers 命令查看触发器的状态、语法等信息,但是因为不能查询指定的触发器,所以每次都返回所有的触发器的信息,使用起来不是很方便

删除触发器

drop trigger trigger_name

事务

事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

MySQL 通过 set autocommit、start transaction、commit 和 rollback语句支持本地事务,具体语法如下。 

start transaction | begin [work]
commit [work] [and [no] chain] [[no] release]
rollback [work] [and [no] chain] [[no] [release]]
set autocommit = {0 | 1}

 

默认情况下,MySQL 是自动提交(Autocommit)的,如果需要通过明确的 Commit 和Rollback 提交和回滚事务,那么需要通过明确的事务控制命令来开始事务

start transaction 或 begin 语句可以开始一项新的事务。
commit 和 rollback 用来提交或者回滚事务。

set autocommit 用于修改当前连接的提交方式。如果设置了set autocommit=0,禁止自动提交。

 

如果只是对某些语句需要进行事务控制,则使用 start transaction 语句开始一个事务比较方便,这样事务结束之后可以自动回到自动提交的方式,如果希望所有的事务都不是自动提交的,那么通过修改autocommit来控制事务比较方便,这样不用在每个事务开始的时候再执行start transaction语句。

示例:

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
+----+------+
1 row in set (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into svip(name) values('wu');
Query OK, 1 row affected (0.00 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
|  3 | wu   |
+----+------+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.07 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
+----+------+
1 row in set (0.00 sec)
begin
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into svip(name) values('wu');
Query OK, 1 row affected (0.00 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
|  4 | wu   |
+----+------+
2 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.07 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
+----+------+
1 row in set (0.00 sec)
start transaction
mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
+----+------+
1 row in set (0.00 sec)

mysql> insert into svip(name) values('wu');
Query OK, 1 row affected (0.07 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
|  5 | wu   |
+----+------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> rollback;  #  已经真实的写到了数据表中无法回滚。
Query OK, 0 rows affected (0.00 sec)

mysql> select * from svip;
+----+------+
| id | name |
+----+------+
|  1 | jun  |
|  5 | wu   |
+----+------+
2 rows in set (0.00 sec)
commit

 

详情参照 http://www.runoob.com/mysql/mysql-transaction.html

存储过程

存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql。

优点:

  1. 用于替代程序写的SQL语句,实现程序与SQL解耦
  2. 基于网络传输,传别名的数据量小,而直接传SQL数据量大

缺点:

  1. 程序员扩展不方便

创建无参存储过程

delimiter $$
create procedure proc()
  begin
    declare i int default 1;
    while (i<3) do  # 查询两次
      select name from svip;
      set i=i+1;
    end while ;
  end $$
delimiter ;

# 在MySQL中调用存储过程。
call proc()

# 在Python中通过pymysql调用。
cur = conn.cursor()
cur.callproc('proc')
print(cur.fetchall())  # 存储过程中SQL语句的执行结果
View Code

创建有参存储过程

对于存储过程,可以接收参数,其参数有三类:

#in          仅用于传入参数用
#out        仅用于返回值用
#inout     既可以传入又可以当作返回值
delimiter $$
create procedure proc_args(
    in n char(16),
    out x int
)
  begin
    select name,type from user where name = n;
    set x=1;
  end $$
delimiter ;

# 在MySQL中调用存储过程。
set @name='jun';
set @res=0;

call proc_args(@name,@res);

# 查看返回值。
select @y;

# 在Python中通过pymysql调用。
import pymysql

conn = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    password='123456',
    database='index_test',
    charset='utf8'
)

cur = conn.cursor()
cur.callproc('proc_args', ('jun', 0))

# 存储过程中SQL语句的执行结果
print(cur.fetchall())

# 存储过程的返回值
# set @_proc_args_0
# set @_proc_args_1
cur.execute('select @_proc_args_1;')
print(cur.fetchall())

cur.close()
conn.close()
View Code

删除存储过程

drop procedure proc;

 

posted @ 2018-04-27 20:48  流星之泪  阅读(104)  评论(0编辑  收藏  举报