mysql系列学习 泽桐

# 帮助
help create user;
# 查看当前用户
select user();
# 创建用户
create user 'egon'@'localhost' identified by '123';
create user 'alex'@'%' identified by '123';
create user 'ton'@'192.168.1.%' identified by '123';
# 授权(直接创建用户后面加上identified by '123')
grant select on *.* to 'egon'@'localhost' identified by '123';
grant select (id,name),update (name) on db1.t1 to 'egon'@'localhost';
flush privileges;
# 回收权限
revoke select on db1.* from 'egon'@'localhost';
# 权限对应表
mysql.db/mysql.user/mysql.table_priv/mysql.columns_priv
update mysql.user set authentication_strings=password('123') where user='root' and host='localhost';
# 远程连接
mysql -h192.168.1.1 -ualex -p123
# 增删改查库(文件夹)
create database db1 charset utf8;
show create database db1;
alter database db1 charset gbk;
drop database db1;
# 增删改查表(文件)
use db1;
create table t1(id int primary key auto_increment,name char(10) not null unique)engine=innodb default charset utf8;
show tables;
show create table t1;
alter table t1 add age int;
alter table t1 drop age int;
alter table t1 modify id int primary key auto_increment;
alter table t1 charset utf8;
drop table t1;
# 查看表结构
describe t1; # desc
# 操作文件内容(增删改查)
insert into db1.t1(id,name) values(1,'egon'),(2,'egon2');
truncate t1; # 数据量比较大情况下,删除速度快
# 拷贝表结构和记录(键不会拷贝),创建一个新表
create table t_copy select * from t1;
# 只拷贝表结构,不拷贝记录
create table t_copy select * from t1 where 1=2;
# 查看编码
\s
# 以行显示
;前加上\G

一、数据类型
1、整数类型
TINYINT SMALLINT MEDIUMINT INT BIGINT
注意:为该类型指定宽度时,仅仅只是指定查询结果的显示宽度,与存储范围无关
create table t7(x int(3) zerofill);前面8位用0填充(默认int(11))
2、浮点型
定点数类型 DEC等同于DECIMAL  
浮点类型:FLOAT DOUBLE
create table t4(salary float(5,2));#5代表有效数字位,2代表小数位
insert into t4 values (-3.33);
3、字符串类型(宽度既是字符数)
char:定长,简单粗暴,浪费空间,存取速度快
varchar:可变长,精准,节省空间,存取速度慢
4、日期
datetime 2017-01-01 10:00:00
date:2017-01-01
time:10:00:00
year:2017
insert into student values(1,'alex',now(),now(),now(),now());
insert into student values(1,'alex','2017-01-01','2017','2017-01-01 10:00:00','10:00:00');
insert into student values(1,'alex','2017/01/01','2017','2017-01-01 10:00:00','10:00:00');
insert into student values(1,'alex','20170101','2017','20170101100000','100000');
5、枚举与集合(set可取多个)
create table student(sex enum('male','female'),hobbies set('music','read'));
insert into student values('male','music,read');
insert值不在范围内则存为空

二、表约束条件
1、not null、default
create table student(
sex enum('male','female')not null default 'male',
hobbies set('music','read'));
2、unique
#多列唯一
create table services(
name char(10),
host char(15),
port int,
constraint host_port unique(host,port));
3、auto_increment
auto_increment_offset偏移量(起始值),auto_increment_increment步长
#步长,对指定表生效
create table services(
id int primary key auto_increment)
auto_increment=10;
#查看变量
show variables like '%auto_in%';
#对当前回话生效
set session auto_increment_offset=200;
set session auto_increment_increment=2;
#所有回话生效
set global auto_increment_offset=200;
set global auto_increment_increment=2;
注意:偏移量不能大于步长,否则偏移量会被忽略,默认从1开始
4、foreign key (on delete cascade 删除操作联动)
create table emp_info(
...
dep_id int,
constraint fk_depid_id foreign key(dep_id) references dep_info(id)
on delete cascade
on update cascade
);
create table dep_info(
id int primary key auto_increment,
...
);

三、表查询
1、单表查询
1)group by
#聚合列
select depart_id,group_concat(name) from employee group by depart_id;
#计数
select depart_id,count(name) from employee group by depart_id;
#最大值,最小值min,sum,avg
select depart_id,max(name) from employee group by depart_id;
2)关键字的执行优先级(重点)
from
where
group by
按照select后的字段取新的虚拟表,有聚合函数则将组内数据进行聚合
having
distinct
order by
limit
3)limit(做分页)
select * from emp limit 0,3;#起始,步长(1-3)
4)distinct
select distinct sex from emp;
5)select字段上做运算
select name,salary*12 年薪(annual_salary) from emp;

2、多表查询
1)简单查询
#笛卡尔积拼成一张虚拟表
select * from department,employee;
#内连接:按照on条件取相同部分
select * from department,employee where department.id=employee.dep_id;
select * from employee inner join department on department.id=employee.dep_id;
#左连接:按照on条件取相同部分再保留左表的记录
select * from employee left join department on department.id=employee.dep_id;
#右连接:按照on条件取相同部分再保留右表的记录
select * from employee right join department on department.id=employee.dep_id;
#full连接:按照on条件取相同部分再保留左右两表的记录
select * from employee left join department on department.id=employee.dep_id
union
select * from employee right join department on department.id=employee.dep_id;

2)子查询
select * from employee where dep_id in (select id from department where name in ('技术','销售'));

四、索引
1、原理
目的在于提高查询效率,本质是不断缩小想要获取的数据的范围来筛选结果。
2、索引的数据结构
B+树是通过二叉查找树,再由平衡二叉树,B树演化而来
###b+树性质
1.索引字段要尽量的小
2.索引的最左匹配特性

五、MySQL索引管理
1、MySQL常用的索引

普通索引INDEX:加速查找

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

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

2、索引的两大类型hash与btree
hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)

3、创建/删除索引的语法
创建索引
创建表时:
create table s1(
id int,
name char(6),
index(id)#没有约束的普通索引只能加在最后
);
创建表后:
create index name on s1(name);
create index id_name on s1(id,name);#联合普通索引
create unique index name on s1(name);

删除索引
drop index name on s1;

4、正确使用索引
1 范围问题
2 尽量选择区分度高的列作为索引
3 =和in可以乱序
4 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把
所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’)
5 and/or
条件:
a = 10 and b = 'xxx' and c > 3 and d =4
索引:
制作联合索引(d,a,b,c)
条件:
a = 10 or b = 'xxx' or c > 3 or d =4
索引:
制作联合索引(d,a,b,c)

6 最左前缀匹配原则

联合索引的第二个好处是在第一个键相同的情况下,已经对第二个键进行了排序处理

5、慢查询优化的基本步骤
0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
3.order by limit 形式的sql语句让排序的表优先查
4.了解业务方使用场景
5.加索引时参照建索引的几大原则
6.观察结果,不符合预期继续从0分析

6、慢日志管理
慢日志
- 执行时间 > 10
- 未命中索引
- 日志文件路径

配置:
- 内存
show variables like '%query%';
show variables like '%queries%';
set global 变量名 = 值
- 配置文件
mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini'

my.conf内容:
slow_query_log = ON
slow_query_log_file = D:/....

注意:修改配置文件之后,需要重启服务


六、数据库备份与恢复
#1. 物理备份: 直接复制数据库文件,适用于大型数据库环境。但不能恢复到异构系统中如Windows。
#2. 逻辑备份: 备份的是建表、建库、插入等操作所执行SQL语句,适用于中小型数据库,效率相对较低。
#3. 导出表: 将表导入到文本文件中。
1、使用mysqldump实现逻辑备份
#语法:
# mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql

#示例:
#单库备份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql

#多库备份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

#备份所有库
mysqldump -uroot -p123 --all-databases > all.sql

二、恢复逻辑备份
#方法一:
mysql -uroot -p123 < /backup/all.sql
mysql -uroot -p123 db1 < /backup/db1.sql
#方法二:
mysql> use db1;
mysql> SET SQL_LOG_BIN=0;
mysql> source /root/db1.sql
三、备份/恢复案例
四、实现自动化备份
五、表的导出和导入
六、数据库迁移
http://www.cnblogs.com/linhaifeng/articles/7525619.html


七、pymysql模块
1、execute使用
pip3 install pymysql
import pymysql
user = input('user>>').strip()
pwd = input('password>>').strip()
conn = pymysql.connect(host='localhost',user='root',password='123456',database='day47',charset='utf8')
cursor = conn.cursor() # 游标既mysql>
#执行sql
sql = 'select * from user where user=%s and password=%s;'
rows = cursor.execute(sql, [user,pwd])
print('%s rows in set'%rows) #打印rows是受影响行数
cursor.close()
conn.close()
if row:
print('sucessful')
else:
print('failed')

2、增删改
sql = 'insert into user(name,password) values(%s,%s);'
rows = cursor.executemany(sql, [(user,pwd),(user,pwd)]) #相当于自动循环列表执行execute
print(cursor.lastrowid)#查询最后的自增长ID
print('%s rows in set'%rows) #打印rows是受影响行数
conn.commit()

3、查fetchone,fetchmany,fetchall,没有返回None
sql = 'select * from user;'
rows = cursor.execute(sql)
res1 = cursor.fetchone()#元组
res2_4 = cursor.fetchmany(3)#元组嵌套元组,没有返回None
print('%s rows in set'%rows) #打印rows是受影响行数
conn.commit()

4、光标移动
cursor.scroll(0,mode='absolute')#绝对位置
cursor.scroll(0,mode='relative')#相对位置


八、视图
定义:视图就是一张虚拟表,把经常查询的sql语句存为视图方便再次使用
1、语法:
create view user_dep
as
select user.id uid,user.name uname,dep.id depid,dep.name depname
from user left join dep on user.dep_id=dep.id;
#查看视图
show create table user_dep;
#修改视图
alter view user_dep as 新查询语句;

九、触发器
create
TRIGGER trigger_name
trigger_time trigger_event
on tb1_name for each row
begin
...;
end

delimiter //
create
TRIGGER tri_after_insert_cmd_log
after insert
on cmd_log for each row
begin
if new.is_success='no' then
insert into err_log(cmd_name,sub_time) values(NEW.cmd_name,NEW.sub_time);
end if;
end //
delimiter ;

#删除触发器
delete trigger trigger_name;

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

rollback; #如果任一sql异常,可用此命令回滚
commit; #如果所有sql正常,可用此命令提交


十一、存储过程
存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql
1、无参数
delimiter //
create procedure procedure_name()
begin
...
end //
delimiter ;
#调用存储过程
call procedure_name();
cursor.callproc('p1');

2、有参数
delimiter //
create procedure procedure_name(
in min int,
in max int,
out res int
)
begin
select * from test where id between min and max;
set res=1;
end //
delimiter ;

#调用存储过程
set @n=1 #全局变量
call p1(3,7,@n);
select @n; #查看变量值

#python调用
import pymysql
conn = pymysql.connect(host='localhost',user='root',password='123456',database='db1',charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
res = cursor.callproc('p1', args=(3,7,随意)) #_p1_0=3,_p1_1=7,_p1_2=123
conn.commit()
print(res.fetchall()) #只能拿到存储过程的select结果
rows = cursor.execute('select @_p1_0,@_p1_1,@_p1_2')
print(cursor.fetchall())
cursor.close()
conn.close()

#inout参数
delimiter //
create procedure p1(
inout m int
)
begin
select * from test where id > m;
set m=1;
end //
delimiter ;

#mysql
set @x=2
call p1(@x)
select @x

3、查看存储过程
show create procedure p1\G
#查看所有存储过程(某一类用like)
show procedure status like 'p1%';

4、删除存储过程
drop procedure proc_name;

十二、存储过程应用于事务
delimiter //
create PROCEDURE p5(
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 tb1; #执行失败
insert into blog(name,sub_time) values('yyy',now());
COMMIT;

-- SUCCESS
set p_return_code = 0; #0代表执行成功

END //
delimiter ;

#在mysql中调用存储过程
set @res=123;
call p5(@res);
select @res;

#在python中基于pymysql调用存储过程
cursor.callproc('p5',(123,))
print(cursor.fetchall()) #查询select的查询结果

cursor.execute('select @_p5_0;')
print(cursor.fetchall())

十二、函数
1、内置常用函数
1)数学函数
ROUND(x,y)
返回参数x的四舍五入的有y位小数的值

RAND()
返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。

2)聚合函数(常用于GROUP BY从句的SELECT查询中)
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和
GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果

3)字符串函数
CHAR_LENGTH(str)
查看字符数。
CONCAT(str1,str2,...)
字符串拼接
如有任何一个参数为NULL ,则返回值为 NULL。
CONCAT_WS(separator,str1,str2,...)
字符串拼接(自定义连接符)
CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。

CONV(N,from_base,to_base)
进制转换
例如:
SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示
FORMAT(X,D)
将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。
例如:
SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
INSERT(str,pos,len,newstr)
在str的指定位置插入字符串
pos:要替换位置其实位置
len:替换的长度
newstr:新字符串
特别的:
如果pos超过原字符串长度,则返回原字符串
如果len超过原字符串长度,则由新字符串完全替换
INSTR(str,substr)
返回字符串 str 中子字符串的第一个出现位置。

LEFT(str,len)
返回字符串str 从开始的len位置的子序列字符。
LOWER(str)
变小写
UPPER(str)
变大写
REVERSE(str)
返回字符串 str ,顺序和字符顺序相反。

SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的
格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。


4)日期和时间函数
CURDATE()或CURRENT_DATE() 返回当前的日期
CURTIME()或CURRENT_TIME() 返回当前的时间
DAYOFWEEK(date) 返回date所代表的一星期中的第几天(1~7)
DAYOFMONTH(date) 返回date是一个月的第几天(1~31)
DAYOFYEAR(date) 返回date是一年的第几天(1~366)
DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt) 根据指定的fmt格式,格式化UNIX时间戳ts
HOUR(time) 返回time的小时值(0~23)
MINUTE(time) 返回time的分钟值(0~59)
MONTH(date) 返回date的月份值(1~12)
MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW() 返回当前的日期和时间
QUARTER(date) 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE)
WEEK(date) 返回日期date为一年中第几周(0~53)
YEAR(date) 返回日期date的年份(1000~9999)

5)加密函数
MD5()
计算字符串str的MD5校验和
PASSWORD(str)
返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。

6)控制流函数
CASE WHEN[test1] THEN [result1]...ELSE [default] END
如果test1是真,则返回result1,否则返回default

CASE [test] WHEN[val1] THEN [result]...ELSE [default]END
如果test和val1相等,则返回result,否则返回default

IF(test,t,f)
如果test是真,返回t;否则返回f

IFNULL(arg1,arg2)
如果arg1不是空,返回arg1,否则返回arg2

NULLIF(arg1,arg2)
如果arg1=arg2返回NULL;否则返回arg1
isnull(arg)
空返回true


内置函数重点:
1、char_length:查看字符数
select char_length(name) from t1;
#设置填充字符模式为全字符匹配模式
set sql_mode = 'PAD_CHAR_TO_FULL_LENGTH';
2、length:查看字节数
3、date_format
select date_format('2017-01-01 11:11:11','%Y-%m-%d %H:%i:%S')
example:
提取sub_time字段的值,按照格式后的结果即"年月"来分组
SELECT DATE_FORMAT(sub_time,'%Y-%m'),COUNT(1) FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');

4、自定义函数
delimiter //
create function f1(
x int,
y int)
returns int
begin
declare num int;
set num = x + y;
return (num);
end //
delimiter ;
#删除函数
drop function func_name;
#执行函数
select UPPER('egon') into @res;
SELECT @res;
# 在查询中使用
select f1(11,nid),name from tb2;


十三、流程控制
1、条件语句
delimiter //
create function f5(
i int
)
returns int
begin
declare res int default 0;
if i = 10 then
set res=100;
elseif i = 20 then
set res=200;
elseif i = 30 then
set res=300;
else
set res=400;
end if;
return res;
end //
delimiter ;

2、循环语句
delimiter //
CREATE PROCEDURE proc_while ()
BEGIN

DECLARE num INT ;
SET num = 0 ;
WHILE num < 10 DO
SELECT
num ;
SET num = num + 1 ;
END WHILE ;

END //
delimiter ;

# my.ini

[client]
default-character-set=utf8
user='root'
password='123456'

[mysql]
default-character-set=utf8

[mysqld]
character_set_server=utf8
secure_file_priv='E:\\'

原文地址:https://www.cnblogs.com/linzetong/p/8331201.html