这部分不需要太多理论我还是放在额外的链接里吧

https://blog.csdn.net/qq_42519695/article/details/90062577

开篇

下载安装

linux 安装见上面的博客

windows 安装配置

#1、下载:MySQL Community Server 5.7.16
http://dev.mysql.com/downloads/mysql/

#2、解压
如果想要让MySQL安装在指定目录,那么就将解压后的文件夹移动到指定目录,如:C:\mysql-5.7.16-winx64

#3、添加环境变量
【右键计算机】--》【属性】--》【高级系统设置】--》【高级】--》【环境变量】--》【在第二个内容框中找到 变量名为Path 的一行,双击】 --> 【将MySQL的bin目录路径追加到变值值中,用 ; 分割】
 
添加环境变量后
mysqld --initialize-insecure 初始化
mysqld # 启动MySQL服务
mysql -u root -p # 连接MySQL服务器

"c:\mysql-5.7.16-winx64\bin\mysqld" --install  注册服务
"c:\mysql-5.7.16-winx64\bin\mysqld" --remove   一处服务
net start mysql 启动服务
net stop mysql  关闭服务

安装可能会遇到的问题

占位符....

登陆

设置密码
mysqladmin -uroot password 123

 #修改密码
mysqladmin -uroot -p"旧密码" password "新密码"  #修改密码


mysql -h172.31.0.2 -uroot -p456
mysql -uroot -p
mysql                    以root用户登录本机,密码为空

忘记密码 即配置

mysql8 https://www.cnblogs.com/wangjiming/p/10363357.html

方式一

第一步:mysqld --skip-grant-tables   跳过授权 确保MySQL客户端已经关闭
第二部 :mysql  没有授权的登陆
第三步:
update mysql.user set authentication_string=password('') where user = 'root';  #重新设置密码
# 8版本采用 authentication_string 不同
第4步:flush privileges;   
第5步: 杀死mysql进程  #5 tskill mysqld #或taskkill -f /PID 7832(pid可能不同)
#6 重新启动mysql

方式二 (指定配置文件

配置项中不能出现中文

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8


这只是各个编码的方式
mysqld其他参数 
    port=3306设置端口 
    default-storage-engine=innodb 设置引擎  
    innodb_file_per_table=1  每个表都有一个innodb文件
    basedir=E:\mysql-5.7.19-winx64  #解压路径
    datadir=E:\my_data#data目录


[client]  #有别于mysql客户端 这里可能是其他软件发来的代码指令 比如python
user=root
password=123
port=3306


[mysql]
port=3306
default-character-set=utf8
user=egon
password=4573
#2. 重启服务
#3. 查看修改结果:\s   show variables like '%char%'

库、表、数据、的增删改查

库:
查: show databases;
    show create database db1;
增:create database 脱产7期使用的数据库1  charset=utf8;  有中文一定要设置字符编码
改:alter database db1 charset latin1;    #修改数据库的编码,其他方式见后面
删:drop database db1;


表:
增:create table t1(id int,name char);
查:show tables
    show create table t1;		# 查看表的详细信息
    desc t1;  # 查看表结构
改:alter table t1 modify name char(3);  #整个修改
    alter table t1 change name name1 char(2);  #修改名字 主要和change后面参数有关
删:drop table t1;

 

样本数据:
增:insert into t1 values(1,'egon1'),(2,'egon2'),(3,'egon3');
查:select * from t1;
    select name from t1;
    select * from t1 where id>1 and id<3;
改:update t1 set name='sb' where id=2;
删:delete from t1 where id=1;

清空表:
delete from t1; #删除数据,下次的ID 仍然插入到上一条ID 之后
truncate table t1;  #相当于格式化
auto_increment 表示:自增
primary key 表示:约束(不能重复且不能为空);加速查找

存储引擎:

mysql5.5版本及以上默认的存储引擎是innodb 》》》支持行锁表锁,外键,事物,安全性更高,较myisam数据更安全

myisam:仅仅支持表锁不支持行锁,查询速度较innodb更快

memory:内存引擎,将所有的数据直接放在内存,一旦断电数据全部消失 blackhole:一切存入其中的数据都会消失

创建表的时候使用引擎:create table t1(id int,name char(16))engine=innodb;

 

表的操作

注意:.一张表内字段名不能重复, 字段和类型必须有,最后一个字段不能加,

create table 表名(字段名1 类型[(宽度) 约束条件],字段名2 类型[(宽度) 约束条件],字段名3 类型[(宽度) 约束条件]);

例如:create table db.t33(id int not null,name char(10))

如果 插入的数据长度>要求的字段长度 会怎么样?(严格模式)  

两种情况
1.能够插进去,但是只显示  改为
2.直接报错

改为严格模式
show variables like "%mode%"; 
set global  sql_mode ='STRICT_TRANS_TABLES';  ## 只在当前操作界面有效
set session sql_mode ='STRICT_TRANS_TABLES';  # 全局有效


给为非严格模式
NO_ENGINE_SUBSTITUTION

# 修改完之后退出当前客户端重新登陆即可

在字段后面设置的宽度一定会改变字段存储的大小?

除了整型来说 只是显示限制
create table t6(id int(8)); # 如果存入的数字够8位 正常显示,如果不够8位默认用空格填充

 

字段类型

字段类型分为 :整型 浮点型 字符类型 日期类型 枚举和集合

整型

整型有  tinyint smallint int bigint   默认都是有正负号的  

显示长度不够的话 可以用zerofill填充  id int(8) zerofill 

 

浮点型:精度由低到高

同样插入相同的数据 结果;
create table t10(id float(255,30)); # 总长度为255位 其中小数位占30位
# 1.111111164093017600000000000000
create table t11(id double(255,30)); 1.111111111111111200000000000000
create table t12(id decimal(65,30));1.111111111111111111111111111111

类型存储范围:参考图片http://www.cnblogs.com/linhaifeng/articles/7233411.html

 

字符类型:

char:定长(取值速度较高)      超出宽度 报错。如果不够时用空格填充
varcha( 节约空间 )r:变长 超出宽度 报错。    节约空间  

可以在模式下修改:PAD_CHAR_TO_FULL_LENGTH  可以查看完整长度 

统计字段值所对应的长度 ,设置完成长度的方法

char_length(name) #

取值时会压缩。可以修改模式展示不压缩的数据长度

set global sql_mode="strict_trans_tables,PAD_CHAR_TO_FULL_LENGTH";

日期类型:

create table t15(id int,birth date,class_time time,reg_time datetime,yy year);
create table t13(id int ,birth date,class_time time,reg_time datetime,t_y year);
insert into t13 values(1,"2011-2-13","11:11:11","2019-2-13 11:11:11","2019");
date  "2013-2-13"
time  "11:11:11"
datetime "2013-2-13  11:11:11"
year "2018"

枚举与集合 :

枚举 多选1:

create table t16(
    id int,
    name char(6),
    gender enum('male','female','others')
);


插入
insert into t17 values(1,'tank','male'); 多了会报错

集合:选至少1个:

create table t17(
    id int,
    name char(6),
    gender enum('male','female','others'),
    hobby set('read','DJ','DBJ','run')
);


insert into t17 values(1,'tank','male',"read,DBJ,DJ"); #选多个
insert into t17 values(1,'tank','male',"DBJ");#选一个

约束条件

主键  外键  是否为空  唯一   自动增长 (整数类型,而且为主键 )   默认值   UNSIGNED无符号   ZEROFILL 使用0填充

单列唯一

create table t22(
	id int unique,  # 单个字段
    name char(16)
);
insert into t22 values(1,'egon'),(1,'tank');

联合唯一

create table t23(
    host char(16),
    port int,
    unique(host,port)  # 多个字段
);
insert into t23 values('127.0.0.1',8080),('127.0.0.1',8081);


字段1+字段2 只能出现一次

primary key 主键

单从限制条件上来说,它就相当于not null + unique

没有手动设置主键会怎么样?

innodb引擎中,所有的表都必须有且只有一个主键,它是innodb引擎用来组织数据的依据

注意:.一张表中必须有且只有一个主键,但是可以联合

如果没有主键 会从上到下找到not null + unique 做为主键,如果仍然找不到,会采用自己默认的一个隐藏字段作为主键,

自增只能被增加到 key

create table t26(
            id int primary key,
          name char(16)
    )engine=innodb;

自增  


auto_increment:自增

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


需要退出
设置自增
show session variables like 'auto_inc%';
    
#基于会话级别
set session auth_increment_increment=2 #修改会话级别的步长

基于全局级别的
set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)

设置初始值
set global auto_increment_offset=3;


#需要退出重新登录
注意 初始值 不能大于自增 大于的话 第一个为自增值

联合主键

create table t28(
	ip char(16),
  port int,
  primary key(ip,port)
);
desc t28;

delete from 删除一行字段
truncate   清空表

外键约束

constraint FK_2 foreign key(p_id) references t2(id)



如果把约束删了的话 约束会没了 ,但是你要给他强制在加一个外键的话,必须把表里的数据清空,才能再添加外键

 

================================================================================================

表之间的对应关系

表之间的对应关系-1.将表格都统一卸载一张表的弊端  

组织结构不清晰  可扩展性较差(要求修改某个数据,一张表里就统一修改)且重复数据量

多对一

部门与员工关系 (假设 一个员工只能有一个部门)

e1  字段:   id  员工名字   部门ID
p1  字段:   id  部门名字   

一个员的部门可以有多个? No 
一个部门有个多个员工? yes
只有一个符合一对多的关系才能算一对多


  

 

 

create table dep_table(id int primary key auto_increment, name char(10));


create table emp_table(id int primary key auto_increment, name char(10) ,
p_id int ,foreign key(p_id) references dep_table(id));  创建员工表



怎么解决死关联 无修改字段和删除的问题

当我想修改emp里的dep_id或dep里面的id时返现都无法成功,因为与其他字段已经关联了

创建表的时候
create table emp(
    id int primary key auto_increment,
    name char(16),
    gender enum('male','female') not null default 'male',
    dep_id int,
    foreign key(dep_id) references dep(id)
    on update cascade
    on delete cascade
);


# 删除部门后,对应的部门里面的员工表数据对应删除
# 更新部门后,对应员工表中的标示部门的字段同步更新

多对多

图书馆与图书关系 (假设一本书可以有多个图书出版社)

一本书的出版社可以有多个出版社?YES
一个出版社可以有多个本 yes

两个符合  就是多对多 

先创建谁  ?  外键关联可能会有问题! 答案:创建第三张表


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

create table book(
    id int primary key auto_increment,
    bname char(16),
    price int
);

insert into author(name) values
('egon'),
('alex'),
('wxx')
;
insert into book(bname,price) values
('python从入门到入土',200),
('葵花宝典切割到精通',800),
('九阴真经',500),
('九阳神功',100)
;

create table author2book(
    id int primary key auto_increment,
    author_id int,
    book_id int,
    foreign key(author_id) references author(id)
    on update cascade
    on delete cascade,
    foreign key(book_id) references book(id)
    on update cascade
    on delete cascade
);

insert into author2book(author_id,book_id) values
(1,3),
(1,4),
(2,2),
(2,4),
(3,1),
(3,2),
(3,3),
(3,4);

一对一

一张表的外键只能对应另外一张表的主键 且一张表的主键也只有被另一个表的外键所关联

比如
作者和作者详细的关系(假设一个作者只有一条详情信息)

一本书只能有多条详情信息?   NO 

一条详情信息可以被多个作者关联 ?No

 

create table customer(
    id int primary key auto_increment,
    name char(20) not null,
    qq char(10) not null,
    phone char(16) not null
);

create table student(
    id int primary key auto_increment,
    class_name char(20) not null,
    customer_id int unique, #该字段一定要是唯一的
    foreign key(customer_id) references customer(id) #外键的字段一定要保证unique
    on delete cascade
    on update cascade
);

--! 三种外键关系都是用foreign key,区别在于如何使用以及其他条件限制即可做出三种关系

修改表

# mysql对大小写不敏感!!!
语法:
1. 修改表名  
      ALTER TABLE 表名 
                          RENAME 新表名;
2. 增加字段
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…],
                          ADD 字段名  数据类型 [完整性约束条件…];
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…]  FIRST;
      ALTER TABLE 表名
                          ADD 字段名  数据类型 [完整性约束条件…]  AFTER 字段名;                       
3. 删除字段
      ALTER TABLE 表名 
                          DROP 字段名;
4. 修改字段  # modify只能改字段数据类型完整约束,不能改字段名,但是change可以!
      ALTER TABLE 表名 
                          MODIFY  字段名 数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 旧数据类型 [完整性约束条件…];
      ALTER TABLE 表名 
                          CHANGE 旧字段名 新字段名 新数据类型 [完整性约束条件…];

复制表

# 查询语句执行的结果也是一张表,可以看成虚拟表

# 复制表结构+记录 (key不会复制: 主键、外键和索引)
create table new_service select * from service;

# 只复制表结构
select * from service where 1=2;        //条件为假,查不到任何记录

create table new1_service select * from service where 1=2;  

create table t4 like employees;



#复制
create table t233 like stu; 创建一模一样的表 包括约束

insert into t233 select * from stu;  复制表里的数据

================================================================================================

表查询

书写顺序

select distinct * from '表名' where '限制条件' group by '分组依据' having '过滤条件' order by limit

注意:判断是否为空用 IS NULL 表示

group by分组 +聚合函数

from 》》》where》》》 group by》》》》 select

一般来说如果没有设置严格模式 在分组后依旧能拿出所有字段;set global sql_mode="strict_trans_tables,only_full_group_by";

错误:select * from emp group by post;  

select post,max(salary) from emp group by post;   #获取每个部门的最高工资

聚合其他参数 max min avg sum  count


group_concat 分组下的全部字段   每个部门下所有的学生姓名     


concat()将多个字符串连接成一个字符串


as语法  取个别名

select post as '部门',group_concat(name,'DSB') as '员工姓名' from emp group by post;

having:group by 后的where

from 》》》where》》》 group by》》》》having》》 select

 

distinct  去重

from 》》》where》》》 group by》》》》having》distinct  》 select

select distinct post from emp;

order by  排序

select * from emp order by salary asc;  # 默认是升序
desc  降序

select * from emp order by age desc,salary asc; 1字段的值相同 那么 字段2就以升序排序

limit:限制查询条数

select * from emp limit 5;
select * from emp limit 5,5;
select * from emp limit 5,10;

两个:1 表示起始位置 2 往后获取的数据个数

1个 :前几个

正则(regexp)

略。

 

表查询

查询两张表 ,总数 表一个数*表二个数

select * from emp,dep where emp.dep_id = dep.id;
筛选出符合条件的值,做到拼接

 

内连接:只展示两边相同

select * from emp  inner join par on emp.p_id=par.id ;  只取两张表有对应关系的记录

select * from 表1   inner join  表2  on 表1.字段=表2.字段 

左连接: 左边有 右变没有的字段  也展示  只不过右边字段为null null

left join

右连接: 右边有 左变没有的字段  也展示  只不过左边字段为null null

right join

全连接:

UNION 上下合并且去重

mysql可以使用此种方式间接实现全外连接
select * from employee left join department on employee.dep_id = department.id
union
select * from employee right join department on employee.dep_id = department.id
;

子查询 另外一张表作为此表的筛选条件

select * from emp where dep_id in (select id from dep where name in ('技术','人力资源'));

表的查询结果可以作为其他表的查询条件,

查询一张表
 

select * from tx as a inner join 

select * from tx as b 
on  b.id=a.id
筛选

exist(了解)

EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录,
而是返回一个真假值,True或False。
当返回True时,外层查询语句将进行查询
当返回值为False时,外层查询语句不进行查询。

select * from employee
    where exists
    (select id from department where id > 3);
select * from employee

    where exists
    (select id from department where id > 250);

Nacivat

略,,,

数据备份

http://www.cnblogs.com/linhaifeng/articles/7525619.html

pymysql

import pymysql

conn = pymysql.connect(
    host = '127.0.0.1',
    port = 3306,
    user = 'root',
    password = '123',
    database = 'day41',
    charset = 'utf8',
    autocommit = True #自动提交
)
cursor = conn.cursor(pymysql.cursors.DictCursor) # 生成字典形式的游标
username = input('username>>>:')
password = input('password>>>:')
sql = "insert into userinfo(name,password) values(%s,%s)"  #SQL 语句
# sql = "update userinfo set name='jasonhs' where id =1"
# sql = "select * from userinfo where name=%s and password=%s"
res = cursor.execute(sql,(username,password))  #通过游标向服务器发送sql 语句
# res = cursor.execute(sql)
# conn.commit()  # 确认数据无误之后 commit之后才会将数据真正修改到数据库
if res:
    print(cursor.fetchall())  #通过游标读取结果
    pass
else:
    print('用户名或密码错误!') 


# SQL注入
"""
千万不要手动拼接(关键参数)查询条件
"""
# 增改

据

视图

查询后的表通过视图保存下来 ,对于经常使用的表可以通过视图保存  视图只有表结构文件;

CREATE VIEW v2 as 
SELECT t1.id from t1  INNER JOIN t2 on t1.id=t2.id;

触发器

增、删、改的情况下,自动触发的功能称之为触发器

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 ;  # 结束之后记得再改回来,不然后面结束符就都是$$了




# 针对插入
create trigger tri_after_insert_t1 after insert on 表名 for each row
begin
    sql代码。。。
end ;

删除
略。。

修改
略。。

事务

包含一些sql 语句 如果不成功的话 可以不执行

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

遇到错误不提交代码

create table user(
id int primary key auto_increment,
name char(32),
balance int
);

insert into user(name,balance)
values
('wsb',1000),
('egon',1000),
('ysb',1000);

# 修改数据之前先开启事务操作
start transaction;

# 修改操作
update user set balance=900 where name='wsb'; #买支付100元
update user set balance=1010 where name='egon'; #中介拿走10元
update user set balance=1090 where name='ysb'; #卖家拿到90元

# 回滚到上一个状态
    rollback;

# 开启事务之后,只要没有执行commit操作,数据其实都没有真正刷新到硬盘
commit;
"""开启事务检测操作是否完整,不完整主动回滚到上一个状态,如果完整就应该执行commit操作"""

存储过程

相当于我们的函数

delimiter $$
create procedure p1(
    in m int,  # in表示这个参数必须只能是传入不能被返回出去
    in n int,  
    out res int  # out表示这个参数可以被返回出去,还有一个inout表示即可以传入也可以被返回出去
)
begin
    select tname from teacher where tid > m and tid < n;
    set res=0;   #修改外部变量
end $$
delimiter ;

别处传递out类型参数时

需要把它编程 @变量名=10

然后再 @变量名 传递

 

在python程序中调用存储过程等

pymysql链接mysql
产生的游表cursor.callproc('p1',(2,4,10))  无需事先定义变量
cursor.excute('select @_p1_2;')


存储过程与事务使用举例(了解)

http://www.cnblogs.com/linhaifeng/articles/7495918.html#_label2

流程控制

# if条件语句
delimiter //
CREATE PROCEDURE proc_if ()
BEGIN
    
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END //
delimiter ;

 

# while循环
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 ;

 

索引优化

## 索引与慢查询优化

- primary key  
- unique key
- index key


索引就是一种数据结构,类似于书的目录。意味着以后再查数据应该先找目录再找数据,而不是用翻页的方式查询数据


**索引的影响:**

- 在表中有大量数据的前提下,创建索引速度会很慢
- 在索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低

b+树


只有叶子结点存放真实数据,根和树枝节点存的仅仅是虚拟数据

查询次数由树的层级决定,层级越低次数越少

一个磁盘块儿的大小是一定的,那也就意味着能存的数据量是一定的。如何保证树的层级最低呢?一个磁盘块儿存放占用空间比较小的数据项

思考我们应该给我们一张表里面的什么字段字段建立索引能够降低树的层级高度>>> 主键id字段

#### **聚集索引(primary key)**

聚集索引其实指的就是表的主键,innodb引擎规定一张表中必须要有主键。先来回顾一下存储引擎。

myisam在建表的时候对应到硬盘有几个文件(三个)?

innodb在建表的时候对应到硬盘有几个文件(两个)?frm文件只存放表结构,不可能放索引,也就意味着innodb的索引跟数据都放在idb表数据文件中。

**特点:**叶子结点放的一条条完整的记录

#### 辅助索引(unique,index)

辅助索引:查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息,那么这个时候就无法利用到聚集索引的加速查询效果。就需要给其他字段建立索引,这些索引就叫辅助索引

**特点:**叶子结点存放的是辅助索引字段对应的那条记录的主键的值(比如:按照name字段创建索引,那么叶子节点存放的是:{name对应的值:name所在的那条记录的主键值})

select name from user where name='jason';

上述语句叫覆盖索引:只在辅助索引的叶子节点中就已经找到了所有我们想要的数据

select age from user where name='jason';

上述语句叫非覆盖索引,虽然查询的时候命中了索引字段name,但是要查的是age字段,所以还需要利用主键才去查找

测试索引

## 测试索引

**准备**

```mysql
#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();
```

```mysql 
# 表没有任何索引的情况下
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字段一剑封喉 
```

#### 联合索引

```mysql
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';  # 速度变快
```

总结:上面这些操作,你感兴趣可以敲一敲,不感兴趣你就可以不用敲了,权当看个乐呵。理论掌握了就行了

慢查询日志

设定一个时间检测所有超出改时间的sql语句,然后针对性的进行优化!





ORM

对象关系映射
#定义共有字段
class  Field():
    def __init__(self,name,column_type,primary_key,defalut):
        self.name=name
        self.column_type=column_type
        self.primary_key=primary_key
        self.defalut=defalut

#继承共有字段通过父类的方式实例化
class IntField(Field):
    def __init__(self,name,column_type="int",primary_key=False,defalut="null"):
        super().__init__(name,column_type,primary_key,defalut)

#自定义元类
class My_meteclass(type):
    def __new__(cls, cls_name,cls_base,cls_name_pace):#拦截类的产生
        if cls_name=="Models": #不拦截 非表的类
            return  type.__new__(cls,cls_name,cls_base,cls_name_pace)
        cls_name_pace["table_name"]=cls_name_pace.get("table_name",cls_name) #确保有表名
        primary_key=None #主键占位符
        mapping={} #放置name对应字段对象的字典
        for k,v in cls_name_pace.items(): #确保主键唯一,且把字段K,V形式添加到mapping
            if isinstance(v,Field):
                if v.primary_key:
                    if primary_key:
                        raise TypeError("主键只能有一个")
                    else :
                        primary_key=v.name
                mapping[k]=v
        if not primary_key:
            raise TypeError("主键必须有一个")
        for  k in mapping: #从名称空间里删除字段的键值对
            cls_name_pace.pop(k)
        cls_name_pace["mapping"] = mapping
        cls_name_pace["primary_key"] = primary_key
        return  type.__new__(cls,cls_name,cls_base,cls_name_pace)  #最后转换出新的类



#表模型
class Models(dict,metaclass=My_meteclass):  #继承字典 字典中的dict(k=value) 可以把任意个键值对转为 
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        def __getattr__(self, item):
        return self.items()

    def __setattr__(self, key, value): #对象.name 的形式 添加名称空间
         self[key]=value
    
       def __getattr__(self, item):
        return self[item]

#实例化表
class Admin_table(Models):
    id=IntField(name="id",primary_key=True)
    username=StringField(name="username")
    password=StringField(name="password")


u=Admin_table(name=name)

 

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐