首页 > 数据库 >视图,触发器,存储过程,流程控制等MySQL小知识点

视图,触发器,存储过程,流程控制等MySQL小知识点

时间:2022-11-29 20:58:42浏览次数:40  
标签:知识点 name s1 视图 索引 MySQL where id select

视图,触发器,存储过程,流程控制等MySQL小知识点

一、SQL注入问题

登录:
import pymysql

conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='db5',
    charset='utf8',
    autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 1.获取用户的用户名和密码
user = input('username>>>').strip()
password = input('password>>>').strip()
# 3.构造sql语句
sql = 'select * from user where name = %s and pwd = %s '
print(sql)
# 4.发送给服务端执行sql语句
cursor.execute(sql,(user,password))
# 5.获取执行结果
res = cursor.fetchall()
if res:
    print('登录成功')
    print(res)
else:
    print('用户名或者密码有误')
注册:
import pymysql

conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='123',
    database='db5',
    charset='utf8',
    autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 1.获取用户的用户名和密码
user = input('username>>>').strip()
password = input('password>>>').strip()
# 3.构造sql语句
sql = "insert into user(name,pwd) values(%s,%s)"
print(sql)
# 4.发送给服务端执行sql语句
cursor.executemany(sql,[('wei','123'),('xin','222')])
# 5.获取执行结果
res = cursor.fetchall()
if res:
    print('登录成功')
    print(res)
else:
    print('用户名或者密码有误')
写上述的登录注册的时候记得一定要先建好表
SQL注入:利用特殊符合的组合产生特殊的含义 从而避开正常的业务逻辑
针对上述的SQL注入问题 核心在于手动拼接了关键数据 交给execute处理即可
cursor.execute(sql,(user,password))
cursor.executemany(sql,[('wei','123'),('xin','222')])

二、视图

视图就是通过查询得到的一张虚拟表,然后保存下来,供下次使用
# 创建视图
create view 视图名 as SQL语句
# 1.视图的表只能用来查询,不能做其他的增删改操作
# 2.视图最好少用,会和真表混淆的,造成干扰
mysql> create view student_class_view as select * from student inner join class on student.class_id = class.cid;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from student_class_view;
+-----+--------+----------+--------+-----+--------------+
| sid | gender | class_id | sname  | cid | caption      |
+-----+--------+----------+--------+-----+--------------+
|   1 | 男     |        1 | 理解   |   1 | 三年二班     |
|   2 | 女     |        1 | 钢蛋   |   1 | 三年二班     |
|   3 | 男     |        1 | 张三   |   1 | 三年二班     |
|   4 | 男     |        1 | 张一   |   1 | 三年二班     |
|   5 | 女     |        1 | 张二   |   1 | 三年二班     |
|   6 | 男     |        1 | 张四   |   1 | 三年二班     |
|   7 | 女     |        2 | 铁锤   |   2 | 三年三班     |
|   8 | 男     |        2 | 李三   |   2 | 三年三班     |
|   9 | 男     |        2 | 李一   |   2 | 三年三班     |
|  10 | 女     |        2 | 李二   |   2 | 三年三班     |
|  11 | 男     |        2 | 李四   |   2 | 三年三班     |
|  12 | 女     |        3 | 如花   |   3 | 一年二班     |
|  13 | 男     |        3 | 刘三   |   3 | 一年二班     |
|  14 | 男     |        3 | 刘一   |   3 | 一年二班     |
|  15 | 女     |        3 | 刘二   |   3 | 一年二班     |
|  16 | 男     |        3 | 刘四   |   3 | 一年二班     |
+-----+--------+----------+--------+-----+--------------+
16 rows in set (0.01 sec)

三、触发器

触发器:针对数据的增删改自动出发的功能
主要有六种情况:增前,增后,改前,改后,删前,删后
语法结构:
delimiter 自定义结束符号
create trigger 触发器的名字 before/after insert/update/delete on 表名 for each row
begin
    sql语句
end  自定义结束符
delimiter ;  # 改为原来的结束符,便于统一

'''触发器内部的SQL语句需要用到;号,但是分号是SQL语句的默认结束符,为了我们完整的写语句,我们就需要修改默认的结束符
delimiter &&
delimiter;   最后改为;
'''
on 表 for each :触发对象,触发器绑定的是指是表中的所有行,因此当每一行发生指定改变时,触发器就会发生。

1.触发器名称:标识触发器名称,用户自行指定;
2.触发时间:触发时间为before或after;
3.触发事件:表示触发事件,取值为insert、update、delete;
4.触发器表名:标识建立触发器的表名,即在哪张表上建立触发器;
5.SQL语句:begin和and包含的多条的SQL语句,可以是一条也可以是多条

'''建立六种触发器:before insert、before update、before delete、after insert、after update、after delete'''
例题:
delimiter $$  # 将mysql默认的结束符由;换成$$
create trigger tri_after_insert_cmd after insert on cmd for each row
begin
    if NEW.success = 'no' then  # 新记录都会被MySQL封装成NEW对象
        insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
    end if;
end $$
delimiter ;  # 结束之后记得再改回来,不然后面结束符就都是$$了

#往表cmd中插入记录,触发触发器,根据IF的条件决定是否插入错误日志
INSERT INTO cmd (
    USER,
    priv,
    cmd,
    sub_time,
    success
)
VALUES
    ('kevin','0755','ls -l /etc',NOW(),'yes'),
    ('kevin','0755','cat /etc/passwd',NOW(),'no'),
    ('kevin','0755','useradd xxx',NOW(),'no'),
    ('kevin','0755','ps aux',NOW(),'yes');
# 查询errlog记录
select * from errlog;
# 查看所有的触发器
show trigger;
# 删除触发器
drop trigger tri_after_insert_cmd;

# 没有插入数据到errlog,但是出现了数据,因为触发器内的有逻辑代码

image

四、事物

1.事物的四大特性(ACID)

事物就是要保证数据的安全
1.原子性:事物中的各项操作是不可分割的整体,要么同时成功,要么同时失败
2.一致性:使数据库从一个一致性状态变到另一个一致性状态
3.隔离性:多个事物之间彼此不干扰
4.持久性:也称永久性,指一个事物一旦提交,它对数据库的改变就是永久性的

2.事物的流程

1.开启:任意一条DML语句(insert,update,delete)执行,标志事物开启,或者用begin标志着开启
2.commit (提交):成功的结束,将所有的DML语句的操作与硬盘数据同步(真正的存到硬盘中)
rollback(回滚):失败的结束,将所有的DML语句回滚到进行事物前,也就是相当于没有对数据进行操作。

3.创建事物

mysql> create table user(
    -> id int primary key auto_increment,
    -> name char(32),
    -> balance int
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> insert into user(name,balance)
    -> values
    -> ('jason',1000),
    -> ('kevin',1000),
    -> ('tank',1000);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0
            
# 修改数据之前先开启事务操作
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update user set balance=900 where name='jason'; #买支付100元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1010 where name='kevin'; #中介拿走10元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> update user set balance=1090 where name='tank'; #卖家拿到90元
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from user;
+----+-------+---------+
| id | name  | balance |
+----+-------+---------+
|  1 | jason |     900 |
|  2 | kevin |    1010 |
|  3 | tank  |    1090 |
+----+-------+---------+
3 rows in set (0.00 sec)

mysql> rollback;    # 回滚事物
Query OK, 0 rows affected (0.01 sec)

mysql> select * from user;
+----+-------+---------+
| id | name  | balance |
+----+-------+---------+
|  1 | jason |    1000 |
|  2 | kevin |    1000 |
|  3 | tank  |    1000 |
+----+-------+---------+
3 rows in set (0.00 sec)

4.事物处理的关键词汇

1.事物(transaction):用户定义的一个数据库操作序列
2.回退(rollback):事物回退是指撤销该事物已经完成对该数据库的操作
3.提交(commit):将数据永久性的保存到数据库中
4.保留点(savepoint):为了支持回退部分事物处理,必须能在事物处理块中合适的位置放置占位符,这样如果需要回退,可以回退到某个占位符(保留点)。创建占位符可以使用savepoint,插在SQL语句中。
创建占位符:
   savepoint sp01;
回退到保留点:
   rollback to sp01;
# 保留点在执行rollback或者commit之后自动释放
事物默认字典提交
set autocommit = 1;  # 自动提交开启(默认为开启)
set autocommit = 0;  # 自动提交关闭

5.事物的特性之隔离性

1.读未提交(read uncommitted)
读未提交(read uncommitted)
事务中修改即使没有提交,对其他事务都是可见的,事务可以读取未提交的数据,而导致前后两次读取的数据不一致的情况,这一现象也称为"脏读"。
当执行一个事物时,修改了数据但是并没有提交,另一个事物执行时读取的数据就是修改但是并没有提交的数据。

img

2.读已提交(read committed)
大多数据库系统默认的隔离级别,一个事物从开始直到提交之前所作的任何修改对其他事务都是不可见的,一个事务读取到其他事务以提交的数据导致前后两次读取的数据不一样,这种级别也叫做"不可重复读"。
当执行一个事物时,修改了数据但是没有提交,另一个事物执行时读取的数据是硬盘内的数据,就是没有修改的数据。但是将来要将数据刷到硬盘则需要用到标志位。

img

3.可重复读(repeatable read) # mysql默认隔离级别
能够解决"脏读"问题,但是无法解决"幻读"。
所谓幻读指的是当某个事物读取某个范围内的记录时另外一个事物又在该范围内插入了新的记录,导致前后两次读取的数据不一致,当之前的事物再次读取该范围的记录时会产生幻读。
InnoDB和XtraDB通过多版本并发控制(MVCC)及间隙锁策略解决幻读问题。

img

4.可串行读(serializable)
强制事物串行执行,很少使用该级别。
通过全局标志位加多版本并发控制(MVCC)及间隙锁策略就能够实现多个事物并发执行的效果,并且不会出现错乱。

img

五、InnoDB的MVCC(Multi-Version Concurrency Control)多版本并发控制

目的:为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。
实现原理:在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号,每开启一个新事务,事务的版本号就会递增,并把查询到的数据复制到内存中,后续的所有增删改查操作都是针对于内存中的数据,再把修改行为记录到持久在硬盘上的事务日志中(redo log),而不用每次都将修改的数据本身持久到磁盘。在事务提交时进行一次flush操作,根据redo log保存到磁盘中。
MVCC只能在read committed(提交读)、repeatable read(可重复读)两种隔离级别下工作,其他两个不兼容(read uncommitted:总是读取最新  serializable:所有的行都加锁)

InnoDB的MVCC通过在每行记录后面保存两个隐藏的列来实现MVCC:
    一个列保存了行的创建时间
    一个列保存了行的过期时间(或删除时间)  # 本质是系统版本号
每开始一个新的事务版本号都会自动递增,事务开始时刻的系统版本号会作为事务的版本号用来和查询到的每行记录版本号进行比较。

六、存储过程

存储过程包含了一系列可执行的SQL语句,存储过程存放于MySQL中,通过调用他的名字可以执行其内部的一堆sql,类似于Python中的自定义函数
delimiter  临时结束符
# 声明存储过程
create procedure 名字(参数,参数)
begin
    sql语句
end 临时结束符
delimiter ;

1.变量赋值
set @变量名 = 1;
2.定义变量
declare 变量名 int unsigned default 100;
3.存储过程体
create function 存储函数名
4.调用存储过程
call 存储过程名
5.删除存储过程
drop procedure 名称
6.查看某库中存储过程
show procedure status where db = '数据库名'
7.查看特定的存储过程
show create procedure 数据库名.存储过程名
8.查看存储过程具体信息
show create procedure 名称;
9.查看所有的存储过程
show procedure status;
代码演示:
mysql> select left('foobarbar',5);
+---------------------+
| left('foobarbar',5) |
+---------------------+
| fooba               |
+---------------------+
1 row in set (0.00 sec)

mysql> delimiter $
mysql> create procedure p1()
    -> begin
    -> select * from cmd;
    -> end $
Query OK, 0 rows affected (0.00 sec)

mysql> delimiter;
    -> delimiter ;
    -> $
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'delimiter;delimiter' at line 1
mysql> delimiter ;
mysql> call p1();
+----+-------+------+-----------------+---------------------+---------+
| id | USER  | priv | cmd             | sub_time            | success |
+----+-------+------+-----------------+---------------------+---------+
|  1 | kevin | 0755 | ls -l /etc      | 2022-11-29 17:39:26 | yes     |
|  2 | kevin | 0755 | cat /etc/passwd | 2022-11-29 17:39:26 | no      |
|  3 | kevin | 0755 | useradd xxx     | 2022-11-29 17:39:26 | no      |
|  4 | kevin | 0755 | ps aux          | 2022-11-29 17:39:26 | yes     |
+----+-------+------+-----------------+---------------------+---------+
4 rows in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

# 有参函数
delimiter $$
create procedure p2(
    in m int,  # in表示这个参数必须只能是传入不能被返回出去
    in n int,  
    out res int  # out表示这个参数可以被返回出去,还有一个inout表示即可以传入也可以被返回出去
)
begin
    select * from cmd where id > m and id < n;
    set res=0;  # 用来标志存储过程是否执行
end $$
delimiter ;

# 针对res需要先提前定义
set @res=10;  定义
select @res;  查看
call p1(1,5,@res)  调用
select @res  查看

"""
查看存储过程具体信息
	show create procedure pro1;
查看所有存储过程
	show procedure status;
删除存储过程
	drop procedure pro1;
"""

七、内置函数

1.移除指定字符

Trim,LTrim,RTrim

2.大小写转换

Upper,lower

3.获取左右起始指定个数字符

Left,Right

4.返回读音相似值

Soundex
eg:
客户表中有一个顾客登记的用户名为J.Lee,但如果这是输入错误真名其实叫J.Lie,可以使用soundex匹配发音类似的。
where Soundex(name)=Soundex('J.Lie')

5.日期格式:date_format

'''在MySQL中表示时间格式尽量采用2022-11-11形式'''
CREATE TABLE blog (
    id INT PRIMARY KEY auto_increment,
    NAME CHAR (32),
    sub_time datetime
);
INSERT INTO blog (NAME, sub_time)
VALUES
    ('第1篇','2015-03-01 11:31:21'),
    ('第2篇','2015-03-11 16:31:21'),
    ('第3篇','2016-07-01 10:21:31'),
    ('第4篇','2016-07-22 09:23:21'),
    ('第5篇','2016-07-23 10:11:11'),
    ('第6篇','2016-07-25 11:21:31'),
    ('第7篇','2017-03-01 15:33:21'),
    ('第8篇','2017-03-01 17:32:21'),
    ('第9篇','2017-03-01 18:31:21');
mysql> select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');
+-------------------------------+-----------+
| date_format(sub_time,'%Y-%m') | count(id) |
+-------------------------------+-----------+
| 2015-03                       |         2 |
| 2016-07                       |         4 |
| 2017-03                       |         3 |
+-------------------------------+-----------+
3 rows in set (0.00 sec)

1.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(sub_time)=07;
# 更多日期处理相关函数 
	adddate		增加一个日期 
	addtime 	增加一个时间
	datediff  	计算两个日期差值

八、流程控制

# 分支结构
declare i int default 0;
if i = 1 then
     select 1;
elseif i = 2 then
      select 2;
else 
      select 7;
end if;
# 循环结构
declare num int;
set num = 0;
while num < 10 do
     select num ;
     set num = num + 1;
end while;

九、索引

1.索引

1)索引就好比一本书的目录,它能让你更快的找到自己想要的内容
2)让获取的数据更有目的性,从而提高数据库检索数据的性能

索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构
	* primary key
	* unique key
	* index key
1.上述的三个key都可以加快数据查询
2.primary key和unique key除了可以加快查询本身还自带限制条件而index key很单一就是用来加快数据查询
3.外键不属于索引键的范围 是用来建立关系的 与加快查询无关

索引加快查询的本质
	id int primary key auto_increment,
 	name varchar(32) unique,
  	province varchar(32)
 	age int
 	phone bigint
 	
	select name from userinfo where phone=18818888888;  # 一页页的翻
	select name from userinfo where id=99999;  # 按照目录确定页数找

索引可以加快数据查询 但是会降低增删的速度
通常情况下我们频繁使用某些字段查询数据
	为了提升查询的速度可以将该字段建立索引
    
聚集索引(primary key)
	主键、主键索引
    聚集索引其实指的就是表的主键,innodb引擎规定一张表中必须要有主键。
辅助索引(unique,index)
	除主键意外的都是辅助索引,查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息,那么这个时候就无法利用到聚集索引的加速度查询结果。就需要给其他字段建立索引,这些索引就叫辅助索引。
覆盖索引
	select name from user where name='jason';
非覆盖索引
	select age from user where name='jason';

2.索引底层原理

树:是一种数据结构,主要用于优化数据查询的操作。
1.二叉树
本身是有序树,数中的各个节点不能超过两个分支。
特点:
二叉树中,第i层最多有2^( i-1)个节点
如果二叉树的深度为K,那么次二叉树最多有2^K-1 个节点
二叉树中,终端结点数(叶子结点数)为n0,度为2的结点数为n2,则n0=n2+1
除了叶子结点可以有多个分支,其他节点最多只能两个分支。所有的节点都可以直接存放完整数据(每一个数据块是有固定大小的)。

2.B树(B-树)
除了叶子结点可以有多个分支,其他节点最多只能两个分支。所有的节点都可以直接存放完整数据(每一个数据块是有固定大小的)。
所有的节点都可以存放这个数据的完整数据,有缺点,磁盘块大小是固定的,意味这一个节点里存储的数据很少。树的层级越高,查询的次数越多。树的层级越低,查询的越快。
特点:
关键字集合分布在整颗树中;
任何一个关键字出现且只出现在一个结点中;
搜索有可能在非叶子结点结束;
其搜索性能等价于在关键字全集内做一次二分查找;
自动层次控制;

3.B+树
只有叶子节点存放真正的数据,其他节点只存主键值(辅助索引值)。
节点能够存储更多的主键值,说明树的层级越低,查询的速度越快。
id作为主键,因为id是整型,存储的字节小,可以在一个磁盘外里能够存放更多的主键值。
一个磁盘块的容量是有限的,那么尽可能存储更多的信息,降低树的层级,提升数据查找效率,降低查找时间。
所有关键字都出现在叶子结点的链表中,且链表中的关键字恰好是有序的;
不可能在非叶子结点命中;
非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
更适合文件索引系统;

img

十、慢查询优化

explain select name,countrycode from city where id=1;
序列 常见的索引扫描类型
1 index
2 range
3 ref
4 eq_ref
5 const
6 system
7 null
从上到下,性能从最差到最好,我们认为至少要达到range级别
index:Full Index Scan,index与all区别为index类型只遍历索引树。

range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,显而易见的索引范围扫描是带有between或者where子句里带有<,>查询。
alter table city add index idx_city(population);
explain select * from city where population>30000000;

ref:使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行。
alter table city drop key idx_code;
explain select * from city where countrycode='chn';
explain select * from city where countrycode in ('CHN','USA');
explain select * from city where countrycode='CHN' union all select * from city where countrycode='USA';

eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者unique key作为关联条件A
explain select * from A join B on A.sid=B.sid;
const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量。
explain select * from city where id=1000;

null:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
explain select * from city where id=1000000000000000000000000000;

十一、测试索引

#1. 准备表
create table s1(
id int,
name varchar(20),
gender char(6),
email varchar(50)
);

#2. 创建存储过程,实现批量插入记录
delimiter $$ #声明存储过程的结束符号为$$
create procedure auto_insert1()
BEGIN
    declare i int default 1;
    while(i<3000000)do
        insert into s1 values(i,'jason','male',concat('jason',i,'@oldboy'));
        set i=i+1;
    end while;
END$$ #$$结束
delimiter ; #重新声明分号为结束符号

#3. 查看存储过程
show create procedure auto_insert1\G 

#4. 调用存储过程
call auto_insert1();
# 表没有任何索引的情况下
select * from s1 where id=30000;
# 避免打印带来的时间损耗
select count(id) from s1 where id = 30000;
select count(id) from s1 where id = 1;

# 给id做一个主键
alter table s1 add primary key(id);  # 速度很慢

select count(id) from s1 where id = 1;  # 速度相较于未建索引之前两者差着数量级
select count(id) from s1 where name = 'jason'  # 速度仍然很慢


"""
范围问题
"""
# 并不是加了索引,以后查询的时候按照这个字段速度就一定快   
select count(id) from s1 where id > 1;  # 速度相较于id = 1慢了很多
select count(id) from s1 where id >1 and id < 3;
select count(id) from s1 where id > 1 and id < 10000;
select count(id) from s1 where id != 3;

alter table s1 drop primary key;  # 删除主键 单独再来研究name字段
select count(id) from s1 where name = 'jason';  # 又慢了

create index idx_name on s1(name);  # 给s1表的name字段创建索引
select count(id) from s1 where name = 'jason'  # 仍然很慢!!!
"""
再来看b+树的原理,数据需要区分度比较高,而我们这张表全是jason,根本无法区分
那这个树其实就建成了“一根棍子”
"""
select count(id) from s1 where name = 'xxx';  
# 这个会很快,我就是一根棍,第一个不匹配直接不需要再往下走了
select count(id) from s1 where name like 'xxx';
select count(id) from s1 where name like 'xxx%';
select count(id) from s1 where name like '%xxx';  # 慢 最左匹配特性

# 区分度低的字段不能建索引
drop index idx_name on s1;

# 给id字段建普通的索引
create index idx_id on s1(id);
select count(id) from s1 where id = 3;  # 快了
select count(id) from s1 where id*12 = 3;  # 慢了  索引的字段一定不要参与计算

drop index idx_id on s1;
select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';
# 针对上面这种连续多个and的操作,mysql会从左到右先找区分度比较高的索引字段,先将整体范围降下来再去比较其他条件
create index idx_name on s1(name);
select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';  # 并没有加速

drop index idx_name on s1;
# 给name,gender这种区分度不高的字段加上索引并不难加快查询速度

create index idx_id on s1(id);
select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';  # 快了  先通过id已经讲数据快速锁定成了一条了
select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 慢了  基于id查出来的数据仍然很多,然后还要去比较其他字段

drop index idx_id on s1

create index idx_email on s1(email);
select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 快 通过email字段一剑封喉 
联合索引:
select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  
# 如果上述四个字段区分度都很高,那给谁建都能加速查询
# 给email加然而不用email字段
select count(id) from s1 where name='jason' and gender = 'male' and id > 3; 
# 给name加然而不用name字段
select count(id) from s1 where gender = 'male' and id > 3; 
# 给gender加然而不用gender字段
select count(id) from s1 where id > 3; 

# 带来的问题是所有的字段都建了索引然而都没有用到,还需要花费四次建立的时间
create index idx_all on s1(email,name,gender,id);  # 最左匹配原则,区分度高的往左放
select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 速度变快

十二、全文检索

MySQL的全文检索功能MYISAM存储引擎支持而InnoDB存储引擎不支持
一般在创建表的时候启用全文检索功能
create table t1(
	id int primary key auto_increment,
  content text
	fulltext(content)
)engine=MyISAM;

# match括号内的值必须是fulltext括号中定义的(单个或者多个)
select content from t1 where match(content) against('jason')
'''上述语句可以用like实现但是查询出来的结果顺序不同 全文检索会以文本匹配的良好程度排序数据再返回效果更佳'''

# 查询扩展
select note_text from productnotes where Math(note_text) Against('jason' with query expansion);
"""
返回除jason外以及其他jason所在行相关文本内容行数据
eg:
	jason is handsome and cool,every one want to be cool,tony want to be more handsome;
	二三句虽然没有jason关键字 但是含有jason所在行的cool和handsome
"""

# 布尔文本搜索
即使没有定义fulltext也可以使用,但是这种方式非常缓慢性能低下
select note_text from productnotes where Match(note_text) Against('jason' in boolean mode);

# 注意事项
1.三个及三个以下字符的词视为短词,全文检索直接忽略且从索引中排除
2.MySQL自身自带一个非用词列表,表内词默认均被忽略(可以修改该列表)
3.出现频率高于50%的词自动作为非用词忽略,该规则不适用于布尔搜索
4.针对待搜索的文本内容不能少于三行,否则检索不返回任何结果
5.单引号默认忽略

十三、插入数据

数据库经常被多个用户访问,insert操作可能会很耗时(特别是有很多索引需要更新的时候)而且还可能降低等待处理的select语句性能
如果数据检索是最重要的(一般都是),则可以通过在insert与into之间添加关键字low_priority指示MySQL降低insert语句优先级
	insert low_priority  into 
  
insert还可以将一条select语句的结果插入表中即数据导入:insert select
eg:想从custnew表中合并数据到customers表中
  insert into customers(contact,email) select contact,email from custnew;

十四、更新数据

如果使用update语句更新多列值,并且在更新这些列中的一列或者多列出现一个错误会导致整个update操作被取消,如果想发生错误也能继续执行没有错误的更新操作可以采用
	update ignore custmoers ...
  """
  update ignore  set name='jason1',id='a' where id=1;
  	name字段正常修改
  update set name='jason2',id='h' where id=1;
  	全部更新失败
  """

十五、锁

读锁(共享锁)    多个用户同一时刻可以同时读取同一个资源互不干扰写锁(排他锁)    一个写锁会阻塞其他的写锁和读锁死锁   
1.多个事务试图以不同的顺序锁定资源时就可能会产生死锁  
2.多个事务同时锁定同一个资源时也会产生死锁    
# Innodb通过将持有最少行级排他锁的事务回滚

十六、数据库三大范式

1.第一范式(1NF):属性不可分割,即每个属性都是不可分割的原子项。(实体的属性即表中的列)
2.第二范式(2NF):满足第一范式,且不存在部分依赖,即非主属性必须完全依赖于主属性
3.第三范式(3NF):满足第二范式;且不存在传递依赖,即非主属性不能与非主属性之间有依赖关系,非主属性必须直接依赖于主属性,不能间接依赖主属性。(A -> B, B ->C, A -> C)

标签:知识点,name,s1,视图,索引,MySQL,where,id,select
From: https://www.cnblogs.com/zx0524/p/16936637.html

相关文章