python必坑知识点04

zhang_Sir / 2023-08-23 / 原文

1.关系型和非关系型数据库区别

关系型:支持常用的sql语句,本质相当于一个二维表模型,表之间可以有关联、外键等
非关系型:可以有多种的状态的命令,k、v键值对等,支持高并发,效率高,可用于集群的分布式均衡负载

2.MySQL数据库事务特性有哪些?

四大特性:
    原子性:不可分割,要么都成功,要么都失败回滚
    一致性:事务执行前后数据完整性一致
    隔离性:事务执行中,不受到外界的干扰
    持久性:事务执行结束,数据持久到数据库中

3.通俗地讲一下三个范式

范式一:记录的原子性,不可拆分
范式二:唯一性
范式三:冗余性

为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。
在实际开发中最为常见的设计范式有三个:

1.第一范式(确保每列保持原子性)

第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。
上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。

2.第二范式(确保表中的每列都和主键相关)

第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
订单信息表
这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。
而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了。如下所示。
这样设计,在很大程度上减小了数据库的冗余。如果要获取订单的商品信息,使用商品编号到商品信息表中查询即可。

3.第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。
这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的记录,也不必在订单信息表中多次输入客户信息的内容,减小了数据冗余。

4.主键、外键和索引的区别

(1)概念
主键:唯一标识一条记录,不能有重复,不允许为空。
外键:表的外键是另一表的主键,外键可以有重复,可以是空值。
索引:该字段没有重复值,但可以有一个空值。

(2)作用
主键:用来保证数据完整性
外键:用于和其他表建立联系用的
索引:提高查询排序的速度

(3)个数
主键:主键只能有一个
外键:一个表可以有多个外键
索引:一个表可以有多个唯一索引

5.commit和rollback的理解

commit:sql执行成功,数据提交到数据库中
rollback:sql执行失败,不会提交到数据库,数据回滚到执行sql之前

6.SQL语句查询优化有哪些方法

建立索引并命中索引,在查询的时候,要尽量让数据库引擎使用索引。加入explain执行计划

1.尽量避免使用select *
2.尽量避免使用!=
3.尽量避免使用or
	优化方式:可以用union代替or。如下:
    SELECT * FROM t WHERE username="hkw"
    UNION
    SELECT * FROM t WHERE nickname="jon"
4.尽量避免使用in和not in
	优化方式:如果是连续数值,可以用between代替
    如果是子查询,可以用exists代替。如下:
	SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.username = t2.username)
5.尽量避免在字段开头模糊查询
	SELECT * FROM t WHERE username LIKE '%li%'
    优化方式:尽量在字段后面使用模糊查询。如下:
    SELECT * FROM t WHERE username LIKE 'li%'
6.尽量避免进行null值的判断
    SELECT * FROM t WHERE score IS NULL
    优化方式:可以给字段添加默认值0,对0值进行判断。如下:
    SELECT * FROM t WHERE score = 0
7.尽量避免在where条件中等号的左侧进行表达式、函数操作
	SELECT * FROM t2 WHERE score/10 = 9
    SELECT * FROM t2 WHERE SUBSTR(username,1,2) = 'li'
    优化方式:可以将表达式、函数操作移动到等号右侧。如下:
    SELECT * FROM t2 WHERE score = 10*9
    SELECT * FROM t2 WHERE username LIKE 'li%'

7.SQL

学生表:student(学号,学生姓名,出生年月,性别)
成绩表:score(主键,学号,课程号,成绩)
课程表:course(课程号,课程名称,教师号)
教师表:teacher(教师号,教师姓名)

(1)学生表和成绩表的建表语句(根据需求定义字段类型,外键约束等)

create table student(
	sid int not null primary key auto_increment,
    sname varchar(32) not null,
    ctime datetime not null,
    gender varchar(8) not null
);
create table score(
	id int not null primary key auto_increment,
    student_id int,
    course_id int,
    num int,
    constraint fk_score_student foreign (student_id) references student(sid),
    constraint fk_score_course foreign (course_id) references course(cid)
);
create table course(
	cid int not null primary key auto_increment,
    cname varchar(32) not null,
    teacher_id int,
    constraint fk_course_teacher foreign (teacher_id) references teacher(tid)
);
create table teacher(
	tid int not null primary key auto_increment,
    tname varchar(32)
);

(2)查姓王的学生名单

select * from student where sname like "王%";

(3)查男同学年龄从小到大排列,第6到第10位同学的所有信息(学生表信息)

select * from student where gender = "F" order by ctime asc;

(4)查姓张老师的个数

select count(*) from teacher where tname like "张%";

(5)查询数学课(课程号001)平均成绩

select avg(score.num) from score 
	left join course on score.course_id=course.cid
where
	course.cid=001

select course_id, avg(num) from score group by course_id having course_id=1;

(6)查每门课程选课人数

select count(*) from score
	left join course on score.course_id=course.cid
group by 
	score.course_cid

select course_id,count(student_id) from score group by course_id;

(7)查各科成绩最高和最低分

select max(num),min(num) from score
	left join course on score.course_id=course.cid
group by course_id

select course_id, min(num), max(num) from score group by course_id;

(8)查询课程成绩小于60分学生的学号、姓名

select student.sid,student.sname from score 
	left join course on score.course_id=course.cid
	left join student on score.student_id=student.sid
where 
	score.num < 60
group by
	course.cid

select * from score inner join student on score.student_id=student.sid where score.num>80;