day02 网编数据库
2020-02-27 12:01 l-pf 阅读(118) 评论(0) 收藏 举报第一部分 必答题
-
简述 OSI 7层模型及其作用?(2分)
应用层:要发送的数据 http/https协议
表示层:
会话层
传输层:端口 udp tcp 四层交换机 四层路由器
网络层:ipv4、ipv6协议 路由器 三层交换机
数据链路层:mac arp协议 网卡 二层交换机
物理层:
应用层(应用层,表示层,会话层)
在应用层中封装实际的消息数据(HTTP,HTTPS,FTP)
传输层:
封装端口 指定传输的协议(TCP/UDP)
网络层:
封装ip 版本ipv4 / ipv6
数据链路层:
封装mac地址 指定链路层协议: arp(通过ip->mac)/rarp(通过mac->ip)
物理层:
打成数据包,变成二进制的字节流通过网络进行传输 -
简述 TCP三次握手、四次回收的流程。(3分)
三次握手:syn ack 在accept和connect之间进行 1.三次握手是tcp协议建立连接的过程 2.由客户端发起一个syn请求,服务端接收并回复(syn、ack) 客户端收到ack和syn之后再回复一个ack 3.再原生的socket代码中三次握手是由accept connect 数据交互:沾包现象、沾包成因 四次挥手:(fin ack)close close 1.四次挥手是tcp断开连接的过程 2.客户端发起一个fin请求,服务端接收并回复ack确认断开请求 之后服务端有发送一个结束fin请求,客户端接收并回复ack 3.再原生的socket代码中四次挥手是有close close 产生 第一次挥手 当客户端向服务端请求断开,这时会发送fin的标记报文。 第二次挥手 当服务端收到客户端fin断开报文时候,可能正在处理数据,此时服务端会发生ack报文。 第三次挥手 当服务端处理完成后,会再次向客户端发送FIN报文,此时可以断开连接。 第四次挥手 当客户端收到服务端的fin报文,会向服务端发送确认ACK,经过两个msl《Maximum Segment Lifetime》时长后断开连接。
SYN 创建连接
ACK 确认响应
FIN 断开连接
三次握手
客户端发送一个消息,请求建立连接
服务端接受客户端的响应,并且发出与客户端建立连接的请求
客户端接受服务端响应,回应服务端请求
接下来就可以发送数据 ...
四次挥手
客户端发送一个消息,请求断开连接
服务端接受客户端响应,回应请求
等到所有数据收发完毕之后
服务端发送断开连接的请求
客户端接受服务端响应,回应请求
等到2msl 最大报文生存时间过后
客户端和服务端彻底断凯连接
-
TCP和UDP的区别?(3分)
TCP协议 上传下载\发邮件 可靠 面向连接 速度慢 能传递的数据长度不限
建立连接 三次握手 syn 请求同步 ack确认同步
消息传递 可靠传输
断开连接 四次挥手 fin 结束标志
实现全双工通讯UDP协议 即时通讯工具 不可靠 面向数据报 速度快 能传递的数据长度有限
不管对方在不在 直接发送
不占连接
随时可以收发消息
一对一 一对多 多对多
tcp 需要建立连接,传输可靠,速度慢,消息面向字节流无边界
udp 不需要建立连接,可靠性差,速度快,消息面向数据报(报文)有边界
4. 什么是黏包?(2分)
当多条消息发送时接受变成了一条或者出现接收不准确的情况
# 黏包:
tcp协议数据因为无边界的特点,导致都填分开发送的数据粘合在一起变成了一条数据
# 现象:
# 情况1:
在发送端,数据小,时间间隔短,容易几个数据粘合在一起
# 情况2:
在接受端,接受数据慢,在缓存区,导致几个数据粘合在了一起
# 解决:
使用struct:
# pack (数据长度在21个亿左右)
"""把任意长度的数字转换成具有4个字节固定长度的字节流"""
res = struct.pack("i",2100000000) #代表当前转化的数据是整型
# unpack
"""把4个字节值恢复成原来的数据,返回的是一个元组"""
tup = struct.unpack("i",res)[0] # 把rev转换成整型int
思路方面:
计算接下来要发送的数据大小是多少
通过pack转化固定4个字节发送给接受段
然后在发送真实数据
接受段需要接受2次,第一次接受转换成的真实数据大小,放recv参数中
第二次在接受真实的数据,才能保证不黏包
场景:
用在及时通讯类中,如果是上传下载不需要.
-
什么 B/S 和 C/S 架构?(2分)
b/s 客户端/服务器
c/s 浏览器/服务器网络开发的两大架构:
c/s : client server 软件
b/s : Brower server 网站,小程序 -
请实现一个简单的socket编程(客户端和服务端可以进行收发消息)(3分)
基于udp的时间服务器 #服务端 import time import socket sk = socket.socket(type=socket.SOCK_DGRAM) sk.bind(('127.0.0.1',9001)) while True: msg,addr = sk.recvfrom(1024) date_fmt = msg.decode('utf-8') tim = time.strftime(date_fmt) sk.sendto(tim.encode('utf-8'),addr) #客户端 import socket sk = socket.socket(type=socket.SOCK_DGRAM) server = ('127.0.0.1',9001) sk.sendto('%Y-%m-%d %H:%M:%S'.encode('utf-8'),server) msg = sk.recv(1024).decode('utf-8') print(msg)服务端 import struct import socket def proto_send(msg): msg = msg.encode("utf-8") len_msg = len(msg) proto_len = struct.pack("i",len_msg) #把字节的长度编程4个字 节#i 代表int conn.send(proto_len) conn.send(msg) sk = socket.socket() sk.bind(("127.0.0.1",9222)) sk.listen() conn,addr = sk.accept() msg1 = "hello" msg2 = "world" proto_send(msg1) proto_send(msg2) # 客户端 import struct import socket sk = socket.socket() def proto_recv(): len_msg = sk.recv(4) len_msg = struct.unpack('i', len_msg)[0] msg = sk.recv(len_msg) return msg sk.connect(('192.168.12.26',9001)) #for i in range(1000000): msg1 = proto_recv() print(msg1) msg2 = proto_recv() print(msg2)
基本实现:
一.TCP 服务端
import socket
# 1.创建一个socket对象
sk = socket.socket()
# 2.绑定ip和端口(注册网络)
sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sk.bind( ("127.0.0.1",9000) )
# 3.开启监听
sk.listen()
# 4.建立三次握手
conn,addr = sk.accept()
# 5.处理收发数据逻辑
# 接受数据
msg = conn.recv(1024)
msg.decode("utf-8")
# 发送数据
conn.send(b"abc")
conn.send("我好帅哦".encode())
# 6.四次挥手
conn.close()
# 7.退还端口
sk.close()
二.TCP 客户端
# 1.创建一个socket对象
sk = socket.socket()
# 2.与服务器进行连接
sk.connect( ("127.0.0.1",9000) )
# 3.收发数据的逻辑
# 发送
sk.send(b"abc")
# 接受
sk.recv(1024)
# 4.关闭链接
sk.close() 1
三.TCP / socketserver 支持TCP的并发操作
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
conn = self.request
if name == "main":
server = socketserver.ThreadingTCPServer( ("127.0.0.1",9000) , MyServer )
server.serve_forever()
四.UDP服务端
import socket
1.创建一个socket对象
sk = socket.socket(type=socket.SOCK_DGRAM)
2.绑定地址
sk.bind( ("127.0.0.1",9000) )
3.处理收发数据的逻辑(服务器一定第一次是接受数据)
接受
msg , cli_addr = sk.recvfrom(1024)
发送
sk.sendto(b"abc" , cli_addr)
4.关闭udp连接
sk.close()
五.UDP客户端
1.创建一个socket对象
sk = socket.socket(type=socket.SOCK_DGRAM)
2.收发数据
sk.sendto("你好".encode("utf-8") , ("127.0.0.1",9000) )
sk.recvfrom(1024)
3.关闭udp连接
sk.close()
"""
最大的网络传输数据包大小 (MTU 1500Byte)
一般路由器网络转发数据的数据包大小不超过1500B
超过这个范围,该数据会进行拆包和打包的过程
"""
7. 简述进程、线程、协程的区别?(3分)
进程是计算机资源分配的最小单位,线程是计算机cpu调度的最小单位,协程是一个线程在代码中来回切换执行的。进程和线程是计算机本身就纯在的,而协程是程序员通过代码写的。
一个进程可以由多个线程,其中线程共享进程的资源,一个进程至少由一个线程,一个应用程序至少由一个进程
由于io操作,同一时刻一个进程中最多由一个线程被cpu调度。
计算密集型:用多进程
IO密集型:用多线程。
进程:资源分配的最小单位,进程之间的数据彼此隔离,可以并发并行
from multiprocessing import Process
线程:程序调度的最小单位,进程里面包含线程,共享同一份进程资源,只能并发(GIL锁)
from threading import Thread
协程:实现单线程在多任务之间的自由切换,是线程执行任务的一种方式
import gevent;from gevent import monkey
monkey.pathch_all() # 识别所有模块中的阻塞
g2 = gevent.spawn(play)
-
什么是GIL锁?(2分)
全局解释器锁:统一时刻保证一个进程只有一个线程可以被cpu调度
计算密集型(经过cpu):用多进程
IO密集型(不经过cpu):用多线程
python中如果创建多线程无法应用计算机的多核优势
并发:同一时间,一个cpu执行多个任务
并行:同一时间,多个cpu执行多个任务
GIL:全局解释器锁,为了保证数据安全,只让多线程并发,不能并行
在后台一个个的程序都是由一个个的cpython解释器执行的,每个解释器运行的程序都是单独的进程
但是同一时间,程序中的多个线程只能由一个cpu执行解决办法:
1.换个jpython等其他解释器,又可能出现兼容性问题
2.用多进程的方式间接实现多线程,资源开销较大
历史遗留问题,无法彻底解决 -
进程之间如何进行通信?(2分)
IPC:内置的模块实现的机制 :队列\管道 第三方工具 : redis rabbitMQ memcacheIPC :
1.管道Pipe(进程和进程之间只能单向通信)(了解)
2.Queue(进程和进程之间可以双向通信)
3.文件 (共享数据)q = Queue(3)
put get
put_nowait get_nowait (linux有兼容性问题)
empty full qsize(队列长度) -
Python如何使用线程池、进程池?(2分)
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
(1)创建进程池/线程池对象 8个
p = ProcessPoolExecutor() # 参数:cpu的逻辑处理器数量
p = ThreadPoolExecutor() # 参数:cpu的逻辑处理器数量 * 5
(2)提交异步任务submit
res = p.submit(func,参数1,参数2,...)
(3)获取返回值 result (里面有阻塞)
res_new = res.result()
(4)等待所有子进程执行完毕 shutdown
p.shutdown()
print("主进程执行结束 .. ")
- 请通过yield关键字实现一个协程? (2分)
"""
创建生成器
(1) 生成器表达式: gen = (i for i in range(10))
(2) 生成器函数 : 函数内含有yield,需要初始化才能使用
"""
def producer():
for i in range(100):
n = yield i
print("结果:%s",n)
def consumer():
# 生成器函数的初始化
g = producer()
# send可以类比next,但是第一次调用时,必须给None,send可以给yield发送数据(上一个yield)
g.send(None)
for i in range(10):
res = g.send(i)
print(res)
consumer()
-
什么是异步非阻塞? (2分)
- 阻塞和非阻塞是指内核提供给应用层的IO访问函数是等待IO结果返回还是立即返回,等待结果的就是阻塞函数,立即返回的就是非阻塞函数,是针对函数而言;
- 同步和异步是指应用层在调用内核的阻塞函数或非阻塞函数后所才取的处理方式,是针对操作而言。
同步:
代码从上到下按照顺序,依次执行
异步:
无需等待当前程序中的代码是否执行完毕,
该代码又开启另外一个进程/线程中执行
阻塞 : input , time , sleep , recv ...
非阻塞 : 依次执行,无需等待
异步非阻塞:
场景发生在多进程/多线程之间
没有任何io阻塞或者等待,同时执行
设置setblocking(False) (设置非阻塞 了解)
13. 什么是死锁?如何避免?(2分)
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
按照顺序加锁
from threading import Lock
互斥锁,死锁,递归锁
只上锁不解锁是死锁
例如:
lock = Lock()
# 1
lock.acquire()
lock.acquire()
lock.acquire()
# 2
进程1
a.acquire()
b.acquire()
b.release()
a.release()
进程2
b.acquire()
a.acquire()
a.release()
b.release()
进程1 拿着A锁抢B锁
进程2 拿着B锁抢A锁
# 使用递归锁,快速应急,解决服务器死锁问题
a = b = RLock()
a.acquire()
a.acquire()
a.acquire()
a.release()
a.release()
a.release()
多次上锁的次数和多次解锁的次数相同,就能达到解锁的目的;
以后使用锁时,尽力不用锁嵌套;
-
程序从flag a执行到falg b的时间大致是多少秒?(2分)
import threading import time def _wait(): time.sleep(60) # flag a t = threading.Thread(target=_wait) t.setDeamon(False) t.start() # flag b 0
守护进程: 守护的是主进程
守护线程: 守护的是所有线程;
0~1秒
import threading
import time
def _wait():
time.sleep(60)
flag a
t = threading.Thread(target=_wait)
t.setDeamon(False)
t.start()
flag b
-
程序从flag a执行到falg b的时间大致是多少秒?(2分)
import threading import time def _wait(): time.sleep(60) # flag a t = threading.Thread(target=_wait) t.setDeamon(True) t.start() # flag b 0
0——1秒
16. 程序从flag a执行到falg b的时间大致是多少秒?(2分)
```python
import threading
import time
def _wait():
time.sleep(60)
# flag a
t = threading.Thread(target=_wait)
t.start()
t.join()
# flag b
60
```
-
读程序,请确认执行到最后number是否一定为0(2分)
import threading loop = int(1E7) def _add(loop:int = 1): global number for _ in range(loop): number += 1 def _sub(loop:int = 1): global number for _ in range(loop): number -= 1 number = 0 ta = threading.Thread(target=_add,args=(loop,)) ts = threading.Thread(target=_sub,args=(loop,)) ta.start() ta.join() ts.start() ts.join() 0
对,是0
18. 读程序,请确认执行到最后number是否一定为0(2分)
```python
import threading
loop = int(1E7)
def _add(loop:int = 1):
global number
for _ in range(loop):
number += 1
def _sub(loop:int = 1):
global number
for _ in range(loop):
number -= 1
number = 0
ta = threading.Thread(target=_add,args=(loop,))
ts = threading.Thread(target=_sub,args=(loop,))
ta.start()
ts.start()
ta.join()
ts.join()
不一定是0
```
-
MySQL常见数据库引擎及区别?(3分)
1、InnoDB存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),其它存储引擎都是非事务安全表,支持行锁定和外键,MySQL5.5以后默认使用InnoDB存储引擎。
InnoDB特点: 支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。
如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。
2、MyISAM存储引擎
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务,不支持外键。
MyISAM特点: 插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用
3、MEMORY存储引擎
MEMORY存储引擎将表中的数据存储到内存中,为查询和引用其他表数据提供快速访问。
MEMORY特点: 所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。
它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。
myisam : 5.5之前的默认存储引擎 , 只支持表级锁(读写互相阻塞)
innodb : 5.5版本之后,默认的存储引擎,支持事务,行级锁,外键,能够抗住更大的并发量(全表扫描,存在表级锁)
memory : 把数据存储在内存里,一般做缓存
blackhole : 黑洞,用来同步数据,应该在主从数据库当中
20. 简述事务及其特性? (3分)
一.什么是事务
事务(Transaction)是并发控制单位,是用户定义的一个操作序列,这些操作要么都做,要么都不做,是一个不可分割的工作单位。
事务通常以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
二.事务的 ACID
事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。
原子性
事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 。
一致性
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。比如,当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统在运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
隔离性
一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
持续性
指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
事务中的所有操作要么全部执行,要么都不执行; 如果事务没有原子性的保证,那么在发生系统 故障的情况下,数据库就有可能处于不一致状态。 因而,事务的原子性与一致性是密切相关的。
A.原子性:
同一个事务当中可能执行多条sql语句,要么全部成功,要么直接回滚,这个过程看成一个整体,一个不能再分割的最小个体
C.一致性:
a,i,d 都是为了保证数据的一致性提出来的
比如必须按照约束要求插入数据,保证每跳数据类型的一致性
事务角度上,防止脏读,幻读,不可重读,最终决定当前客户端和当前的数据库状态一致
I.隔离性:
lock + isolation锁,来处理事务的隔离级别;
一个事务和另外一个事务在工作过程中彼此隔离独立
如果同时更改同一个数据,因为锁机制的存在,先执行的先改,其他事务需要等待,保证数据安全
D.持久性:
把数据写在磁盘上,保证数据的持久化存储;
-
事务的隔离级别?(2分)
事务隔离级别 脏读 不可重复读 幻读 读未提交(read-uncommitted) 是 是 是 不可重复读(read-committed) 否 是 是 可重复读(repeatable-read) 否 否 是 串行化(serializable) 否 否 否
脏读: 没提交的数据读出来的 (查)
不可重读: 前后多次读取,数据内容不一样(同一个会话中,在不进行修改或者删除的时候,永远看到的是同一套数据)
幻读:前后多次读取,数据内容不一样(从添加的角度上说的)
开始事务
begin:
处理sql
commit 提交数据
rollback 回滚数据
数据的隔离级别
RU(READ_UNCOMMITTED) : 读未提交 : 脏读,不可重读,幻读
RC(READ_COMMITTED) : 读已提交 : 防止脏读,会出现不可重复还有幻读
RR(REPEATABLE_READ) : 可重复读 : 防止脏读,不可重复读,可能会出现幻读(默认隔离级别)
SR(SERLALIZABLE) : 可序列化 : 什么都能防止(多个窗口同步,不能并发,性能差)
查看默认的隔离级别
select @@tx_isolation
查询是否自动提交数据
select @@autocommit
找到my.ini 配置文件
autocommit=0 # 关闭自动提交数据
transaction_isolation = READ_UNCOMMITTED # 设置隔离级别
打开窗口1
begin;
update t1 set name = "abc" where id = 1
commit;
打开窗口2
select * from t1;
22. char和varchar的区别?(2分)
都是定义字符串的
char:定长、节省事件、浪费空间 char(255)
vachar:变长、节省空间、浪费事件 vachar(65535)
char 定长,速度快
varchar 变长,速度慢,节省空间(内容的开头会有1~2个字节存储数据长度)
23. mysql中varchar与char的区别以及varchar(50)中的50代表的含义。(2分)
最大50字符
varchar(50) 最多存50个字符
(字符长度如果小于255个,前头用1个字节存长度
字符长度如果大于255个,前头用2个字节存长度
1111 1111 => 255
1111 1111 1111 1111 => 65535
255 ~ 65535 字符长度
)
24. MySQL中delete和truncate的区别?(2分)
delete 删除数据
truncate 重置表(删除数据+重置自增id)
25. where子句中有a,b,c三个查询条件, 创建一个组合索引abc(a,b,c),以下哪种会命中索引(3分)
```
(a)
(b)
(c)
(a,b)
(b,c)
(a,c)
(a,b,c)
第一个和最后一个
```
(a) 命中
(b) 不行
(c) 不行
(a,b) 命中
(b,c) 不行
(a,c) 命中
(a,b,c) 命中
26. 组合索引遵循什么原则才能命中索引?(2分)
同时被调用或第一个被第哦啊用才能命中
最左前缀原则,条件不能使用范围,可以使用and
where a>1 and b=1 and c = 100 不能命中
where b=1 and c = 100 or a = 10 不能命中
-
列举MySQL常见的函数? (3分)
count
avg
sum
max
min
now()
concat
concat_ws
user => select user()
databases => select databases()
group_concat
year(),month,day(),hour,minute,second week...
password -
MySQL数据库 导入、导出命令有哪些? (2分)
导出 (\q退出数据库)
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 表1 表2 表3 > ceshi100.sql
导入 (进入到mysql,选好数据库)
source /home/wangwen/work/abc.sql
29. 什么是SQL注入?(2分)
sql注入:通过注入一些特殊的字符,绕开sql的判断机制
使用预处理机制,可以尽量避免sql注入
execute 默认参数是一条sql语句,如果加入参数元组,就等于开启预处理
语法:execute(sql,(参数1,参数2,参数3......))
import pymysql
user = input("user>>>:").strip()
pwd = input("password>>>:").strip()
conn = pymysql.connect(host="127.0.0.1",user="root",password="",database="db2")
创建游标对象
cursor = conn.cursor()
方法一
"""
user>> sdfsd
password>> sdfsdf' or 10=10 -- sdfsdfsf
sql = "select * from usr_pwd where username = '%s' and password='%s' " % (user,pwd)
res = cursor.execute(sql)
print(res) #返回条数
"""
方法二
sql = "select * from usr_pwd where username = %s and password=%s"
res = cursor.execute(sql,(user,pwd))
if res:
print("登录成功")
else:
print("登录失败")
30. 简述left join和inner join的区别?(2分)
left join : 左联 以左表为主,右表为辅,完整查询左表所有数据,右表不存在的数据拿null来补
inner join : 内联 查询左表右表共同存在的数据 select * from a,b where a.cid = b.id
- SQL语句中having的作用?(2分)
一般和group by 配合使用,将分组之后的数据进行二次过滤用having - MySQL数据库中varchar和text最多能存储多少个字符?(2分)
varchar 存的是字符 21845 最大字节数 65535
text 存的是字符 65535 最大字节数 65535 * 3 - MySQL的索引方式有几种?(3分)
主键primary key 唯一索引 unique 普通索引 index
联合主键primary key(字段1,字段2,...)
联合唯一索引 unique(字段1,字段2,..)
联合普通索引 index(a,b,c)
innodb(聚集索引) : 一个表只有一个聚集索引,和多个辅助索引,排序速度比较快
myisam(辅助索引) : 只能有多个辅助索引,没有聚集索引
myisam 和innodb 使用索引数据结构都是b+树,只是叶子节点存储的数据不同
innodb文件结构中只有.frm 和 .ibd, 直接把数据塞到叶子节点上
myisam文件结构中只有.frm .myd .myi 叶子节点存储的该数据的地址(映射关系)
34. 什么时候索引会失效?(有索引但无法命中索引)(3分)
1.如果查询的是一个大范围内的数据(like in > < ....) 不能命中索引(
2.索引字段参与运算,不能命中,select * from s1 where id*3 = 600
3.如果有or相连,索引字段的判断条件在or的后面,不能命中索引
4.类型不匹配,不能命中 select * from s1 where first_name = 1000
5.联合索引中,不符合最左前缀原则的,不能命中索引
6.like以%开头
35. 数据库优化方案?(3分)
1.读写分离(主从数据库,主数据库查询,从数据库负责增删改)
2.分库分表(将字段数量过多的表进行拆分)
3.合理优化数据类型,尽量少的占用空间以合理改善聚集索引b+树的高度(追求矮胖结构)
36. 什么是MySQL慢日志?(2分)
设定一个时间阀值,执行sql的时间超过该阈值,把该sql记录在日志文件里,就是慢查询日志
# 查看日志开启状态
show variables like 'slow_query_log';
# 开启慢查询日志
set global slow_query_log = "ON";
# 查看时间阈值
show variables like "long_query_time"
# 设置时间的阈值
set global long_query_time = 5
....
# 参考: https://www.cnblogs.com/Yang-Sen/p/11384440.html
37. 设计表,关系如下: 教师, 班级, 学生, 科室。(4分)
科室与教师为一对多关系, 教师与班级为多对多关系, 班级与学生为一对多关系, 科室中需体现层级关系。
```
1. 写出各张表的逻辑字段
2. 根据上述关系表
a.查询教师id=1的学生数
b.查询科室id=3的下级部门数
c.查询所带学生最多的教师的id
```
teacher 老师
id name post_id
1 王老师 1
2 张老师 1
3 金角大王 2
class 班级
id name
1 python1班
2 python2班
3 python3班
t_c_relation 多对多关系
id tid cid
1 1 1
2 1 2
3 3 1
4 3 2
student 学生
id name class_id
1 李四 1
2 张三 2
post 部门
id name parent_id
1 教务部 0
2 python部 1
3 linux部 1
a
select
count(*)
from
t_c_relation as tc,student as s
where
tc.cid = s.class_id
and
tc.tid = 1
b
select
count(*)
from
post
where
parent_id = 3
c
select
tc.tid,count(*) as c
from
t_c_relation as tc,student as s
where
tc.cid = s.class_id
and
tc.tid = 1
group by
tc.tid
order by
c desc
limit 1
38. 有staff表,字段为主键Sid,姓名Sname,性别Sex(值为"男"或"女"),课程表Course,字段为主键Cid,课程名称Cname,关系表SC_Relation,字段为Student表主键Sid和Course表主键Cid,组成联合主键,请用SQL查询语句写出查询所有选"计算机"课程的男士的姓名。(3分)
staff
sid sname sex
1 张三 男
2 李四 女
course
cid cname
1 计算机
2 美术
sc_relation
sid cid
1 1
as 起别名
select
s.sname
from
staff as s,
course as c,
sc_relation as sc
where
sc.sid = s.sid
and c.cid = sc.cid
and c.cname = "计算机"
and s.sex = "男"
as 可以省略
select
s.sname
from
staff s,
course c,
sc_relation sc
where
sc.sid = s.sid
and c.cid = sc.cid
and c.cname = "计算机"
and s.sex = "男"
39. 根据表关系写SQL语句(10分)
<img src="day02.assets/image-20191104220302950.png" alt="image-20191104220302950" style="zoom:50%;" />
- 查询所有同学的学号、姓名、选课数、总成绩;
- 查询姓“李”的老师的个数;
- 查询平均成绩大于60分的同学的学号和平均成绩;
- 查询有课程成绩小于60分的同学的学号、姓名
- 删除学习“叶平”老师课的score表记录;
- 查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;
- 查询每门课程被选修的学生数;
- 查询出只选修了一门课程的全部学生的学号和姓名;
- 查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩;
- 查询两门以上不及格课程的同学的学号及其平均成绩;
第二部分 补充题
-
什么是IO多路复用?
内部的实现是异步非阻塞,通过单个线程管理多个socket连接,而不是创建大量的多进程/多线程,节省资源,提升效率
这些网络io操作都会被selector(内部使用linux的epoll多路复用接口实现的)暂时挂起,推入内存队列
此时服务端可以任意处理调度里面的网络io,
当连接的socket有数据的时候,自然会把对应的socket告诉你然后进行读写,而不至于一直阻塞等待 -
async/await关键字的作用?
asyncio 是在io密集型任务中,处理协程异步并发的工具模块,目的是加快通信的速度,减少阻塞等待
async def 关键字定义异步的协程函数
await 关键字加载需要等待的操作前,控制一个可能发生io阻塞任务的切入和切出 -
MySQL的执行计划的作用?
执行计划 在一条sql执行之前,制定执行的方案
"""desc/emplain + sql"""
desc select * from t1;
把执行计划的类型,优化级别从低->高
all > index > range > ref > eq_ref > const > system
目标: 至少达到range , ref;
range 索引范围扫描(注意点:如果范围太大,不能命中索引)
ref 普通索引查询(非唯一) -
简述MySQL触发器、函数、视图、存储过程?
https://www.cnblogs.com/Eva-J/articles/10435035.html -
数据库中有表:t_tade_date
id tade_date 1 2018-1-2 2 2018-1-26 3 2018-2-8 4 2018-5-6 ... 输出每个月最后一天的ID
select
id,max(tade_date)
from
t_tade_date
group by
month(tade_date)
浙公网安备 33010602011771号