ms001
1、MySQL 三种存储引擎区别
mysql 有三种存储引擎 InnoDB、MyISAM、MEMORY。
三种存储引擎的区别:
1)事物安全:
InnoDB 支持事物安全,MyISAM 和 MEMORY 两个不支持。
2)对外键的支持:
InnoDB 对外键支持情况较好,MyISAM 和 MEMORY 两个不支持外键。
3)存储限制:
InnoDB 有 64TB 的存储限制,MyISAM 和 MEMORY 要是具体情况而定。
4)空间使用:
InnoDB 对空间使用程度较高,MyISAM 和 MEMORY 对空间使用程度较低。
5)内存使用:
InnoDB 和 MEMORY 对内存使用程度较高,MyISAM 对内存使用程度较低。
6)插入数据的速度:
InnoDB 插入数据的速度较低,MyISAM 和 MEMORY 插入数据的速度较高。
Mysql 默认存储引擎:InnoDB 是 Mysql 的默认存储引擎(Mysql5.5.5 之前是 MyISAM)。
如果对事务的完整性要求比较高,要求实现并发控制,或者需要频繁的进行更新、删除操作,或者需要主键自增或者外键,则可以选择 InnoDB。
MyISAM、MEMORY 插入、读取数据速度较快(MEMORY 更快),如果应用的完整性、并发性要求比较低可以选择 MyISAM,如果安全要求低可以选择 MEMORY。
2、redis 两种持久化方式
- RDB 持久化
原理是将 Reids 在内存中的数据库记录定时存储到磁盘上。RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
- AOF(append only file)持久化
原理是将 Reids 的操作日志以追加的方式写入文件。AOF 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
RDB 与 AOF 两种持久化方式的优缺点:
RDB 优缺点:
优点:
节省磁盘空间
恢复速度快
缺点:
如果数据量太庞大,还是比较消耗性能的
因为是按周期备份的,如果因为意外down掉,就会丢失最后一次快照的所有修改
AOF 优缺点:
优点:
备份机制更加稳健,丢失数据概率更低
可读的日志文件,通过操作 AOF 可以处理误操作
缺点:
比起 RDB 占用更多的磁盘空间
恢复速度比较慢
每次增删改都同步的话,有一定的性能压力
存在个别 BUG,造成不能恢复的可能
RDB 与 AOP 两种持久化方式的区别:
1、存储数据
RDB持久化保存键空间的所有键值对(包括过期字典中的数据),并以二进制形式保存,符合rdb文件规范,根据不同数据类型会有不同处理。
AOF持久化保存redis服务器所执行的所有写命令来记录数据库状态,在写入之前命令存储在aof_buf缓冲区。
2、持久化时间选择
RDB持久化通过conf的save选项设置持久化行为(单位时间内的修改次数)。
AOF持久化通过conf的appendfsync选项设置持久化行为(单位时间内的修改次数)。
3、数据还原
RDB持久化:服务器载入rdb文件,阻塞线程,在载入完成之前不接受任何命令。
AOF持久化:服务器创建不带网络连接的伪客户端,读取aof文件中的所有命令并执行(redis服务开启aof持久化在服务器启动时会选择aof文件恢复数据库状态)
4、过期键
RDB持久化在写入或读取时会忽略过期键
AOF持久化不会忽略过期键,在键被惰性删除或定期删除时向aof文件追加一条删除命令
5、文件大小
RDB持久化随着存储数据量的变化而变化(根据不同数据类型有不同的数据压缩优化)
AOF持久化随着执行命令的增加而增加(通过aof重写进行优化)
3、session和cookie
跟踪用户的整个会话,常用的会话跟踪技术是Cookie与Session。
Cookie 通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
4、SQL 优化几种方式
- 对查询进行优化避免全表扫描,首先考虑where和group by上涉及的列进行建立索引
- 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
- in 和 not in 也要慎用,否则会导致全表扫描,连续值可以使用between and
- 查询使用模糊查询,两端使用%%,导致全表扫描
- 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如 where num/2=100
- 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描,如 substring(name,1,3)
https://www.cnblogs.com/kobe24vs23/p/11228577.html
5、编码输出菱形图案
*
***
*****
*******
*****
***
*
def outputStar(num):
for k in range(1, num, 2):
print(('*' * k).center(num))
for k in range(num, 0, -2):
print(('*' * k).center(num))
if __name__ == '__main__':
outputStar(7)
6、多线程有用吗
因为全局解释器锁 GIL 的存在,一个进程只有一个线程进入 CPU 执行,以致有 python 多线程有鸡肋一说。
任何 Python 线程执行前,必须先获得 GIL 锁,然后,每执行100条字节码,解释器就自动释放 GIL 锁,让别的线程有机会执行。这个 GIL 全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在 Python 中只能交替执行,即使 100 个线程跑在 100 核 CPU上,也只能用到 1 个核。
即:不管 CPU 有多少核,Python 多线程实际只能用到 1 个核(因 GIL 锁),所以 Python 多线程有鸡肋一说。
所以,如果是一个计算为主的程序(CPU密集型),那么使用多线程就不是一个明智的选择,此时多线程相当于单线程在跑,由于 CUP 切换的开销,多线程甚至比单线程还要慢。
但是,如果是进行一个 IO 密集型的程序(磁盘或网络为主的程序)就不同了,一个线程在 IO 等待的时候,另一个线程还可以在CPU里执行。IO 的速度比 CPU 是慢太多的,所以,对于执行IO密集型的程序,多线程就发挥作用了。
7、进程
针对操作系统而言,一个进程就是一个任务。一个启动的程序就是一个进程。进程是操作系统的一个执行单元。
from multiprocessing import Process
def eat(name, age='', sex=''):
print(f'{name}, 性别 {sex}, 年龄 {age}')
if __name__ == '__main__':
process = Process(target=eat, args=('tom',), kwargs={'age': 10, 'sex': 'm'})
process.start()
输出结果:
tom, 性别 m, 年龄 10
7.1 join() 函数
join() 会阻塞主进程,直到调用 join() 函数的子进程结束。
未调用 join() 时相当于一个异步操作。调用 join() 后相当于一个同步操作。
未调用 join() 示例:
import time
from multiprocessing import Process
def testFunc():
a = 0
while a < 3:
a += 1
print(f'当前输出 {a}')
time.sleep(0.3)
if __name__ == '__main__':
print('=====================')
process = Process(target=testFunc)
process.start()
print('----------')
输出结果:
=====================
----------
当前输出 1
当前输出 2
当前输出 3
调用 join() 示例:
import time
from multiprocessing import Process
def testFunc():
a = 0
while a < 3:
a += 1
print(f'当前输出 {a}')
time.sleep(0.3)
if __name__ == '__main__':
print('=====================')
process = Process(target=testFunc)
process.start()
process.join()
print('----------')
输出结果:
=====================
当前输出 1
当前输出 2
当前输出 3
----------
7.2 进程间的变量关系
父进程与子进程:每个进程都有自己独立的内存空间,子进程使用父进程的变量,实际是从父进程内存空间拷贝了一份保存在自己的内存空间中,所以不管自己的变量值如何变化,都不会影响父进程的变量,因为这个时候他们本来就是两个不同的变量了。
互相独立的进程:每个进程都有自己独立的内存空间,所以互相独立的进程之间的变量更是互不影响。
结:
进程与进程之间都是有自己独立的内存空间,所以不同进程里的变量是互不影响的。
7.3 进程池
进程池作用:多个客户端并发请求时提高服务器的处的处理效率。
1)示例
import os
import time
from multiprocessing.pool import Pool
def mkProcess(num):
print('开始:进程编号{0},当前进程id:{1}'.format(num, os.getpid()))
time.sleep(num * 2 + 3)
print('结束:进程编号{0},当前进程id:{1}'.format(num, os.getpid()))
if __name__ == '__main__':
print('主进程开始。。。。')
pool = Pool() # 默认情况(空参时),进程池设置的进程数量是当前 CPU 的核心数,示例电脑为4 核
# pool = Pool(4) # 创建一个指定了进程个数的进程池
# 向进程池中添加子进程
for i in range(7):
pool.apply_async(func=mkProcess, args=(i,))
# 调用 join() 前必须先调用 close() 或者 terminate()
pool.close() # 阻止后续任务提交到进程池,当所有任务执行完成后,工作进程会退出。
pool.join() # 等待工作进程结束。
print('主进程结束。。。。')
执行结果:
主进程开始。。。。
开始:进程编号0,当前进程id:4908
开始:进程编号1,当前进程id:5832
开始:进程编号2,当前进程id:5888
开始:进程编号3,当前进程id:5404
结束:进程编号0,当前进程id:4908
开始:进程编号4,当前进程id:4908
结束:进程编号1,当前进程id:5832
开始:进程编号5,当前进程id:5832
结束:进程编号2,当前进程id:5888
开始:进程编号6,当前进程id:5888
结束:进程编号3,当前进程id:5404
结束:进程编号4,当前进程id:4908
结束:进程编号5,当前进程id:5832
结束:进程编号6,当前进程id:5888
主进程结束。。。。
2)进程池之返回值
import time
from multiprocessing import Pool
def testProcess(num):
time.sleep(0.3)
return '我是{}'.format(num)
def mainFunc():
pool = Pool(3)
for i in range(5):
res = pool.apply_async(func=testProcess,args=(i,))
print(res.get())
pool.close()
pool.join()
if res.successful(): # successful():判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError。
print('ok')
if __name__ == '__main__':
mainFunc()
or 使用 with
import time
from multiprocessing import Pool
def testProcess(num):
time.sleep(0.3)
return '我是{}'.format(num)
def mainFunc():
with Pool(3) as pool:
for i in range(5):
res = pool.apply_async(func=testProcess,args=(i,))
print(res.get())
if res.successful(): # successful():判断调用是否已经完成并且未引发异常。 如果还未获得结果则将引发 ValueError。
print('ok')
if __name__ == '__main__':
mainFunc()
输出结果:
我是0
我是1
我是2
我是3
我是4
ok
3)为何调用 close() 后需要调用join()
# 源码
def close(self):
util.debug('closing pool')
if self._state == RUN:
self._state = CLOSE
self._worker_handler._state = CLOSE
self._change_notifier.put(None)
def join(self):
util.debug('joining pool')
if self._state == RUN:
raise ValueError("Pool is still running")
elif self._state not in (CLOSE, TERMINATE):
raise ValueError("In unknown state")
self._worker_handler.join()
self._task_handler.join()
self._result_handler.join()
for p in self._pool:
p.join()
由源码可知,当进程池 close 的时候并未关闭进程池,只是会把状态改为不可再插入元素的状态。join 是一直等到进程池中不再有进程任务,join 才调用结束。(join 阻塞到任务执行完毕)。
close():关闭进程池,阻止新的进程进入进程池。
join():启动子进程并阻塞父进程,直到进程池中的子进程的所有线程执行完毕,才继续执行父进程。
即:join 作用相当于启动进程并实现同步操作。
注意:进程与进程池中调用的 join() 作用不太一样。进程中的作用是阻塞。进程池中的作用是启动子进程并阻塞父进程。
4)进程间的通信
https://docs.python.org/zh-cn/3.8/library/multiprocessing.html?highlight=multiprocessing
multiprocessing 支持进程之间的两种通信通道:Pipe、Queue。
i. Pipe 管道
multiprocessing.Pipe([duplex]):
返回2个连接对象(conn1, conn2),代表管道的两端,默认是双向通信。
如果duplex=False,conn1只能用来接收消息,conn2只能用来发送消息。
from multiprocessing import Process, Pipe
def subProcess(conn):
print('进入子程序 start')
revcData = conn.recv()
print('我是子程序,接收来自主程序的数据:{}'.format(revcData))
conn.send('我是子程序发送的数据BBB')
print('子程序结束 over')
def mainProcess():
print('主程序开始......')
connA, connB = Pipe()
connA.send('我是主程序发送的数据AAA')
print('主程序发送数据结束')
process = Process(target=subProcess, args=(connB,))
process.start()
recvData = connA.recv()
print('我是主程序,接收来自子程序数据:{}'.format(recvData))
print('主程序结束......')
if __name__ == '__main__':
mainProcess()
输出结果:
主程序开始......
主程序发送数据结束
进入子程序 start
我是子程序,接收来自主程序的数据:我是主程序发送的数据AAA
子程序结束 over
我是主程序,接收来自子程序数据:我是子程序发送的数据BBB
主程序结束......
注意:recv()方法会阻塞程序,运行到调用 recv() 这个函数的位置时,会**一直等待接收数据**,如果未接收到数据就会一直等待下去。
ii. Queue 队列
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # prints "[42, None, 'hello']"
p.join()
8、线程
from threading import Thread
def testFunc(name, age=100):
print('启动了一个子线程{},年龄:{}'.format(name, age))
def createThread():
thread = Thread(target=testFunc, args=('tom',), kwargs={'age': 10}, name='testThread') # 参数name 可以指定线程的名字
thread.start()
if __name__ == '__main__':
createThread()
同一进程下的线程都是共享内存空间
进程与进程之间的内存空间是相互独立的
8.1 解决线程共享变量数据错乱问题方法
1)加锁 threading.Lock()
def subTread1():
global num
for i in range(1000000):
lock.acquire() # 加锁
num += 5
num -= 5
lock.release() # 释放锁
print('线程1中num:{}'.format(num))
2)创建线程独立内存副本 threading.local()
import threading
# 创建一个threadLocal
threadlocal = threading.local()
def testFunc(name):
print('{} 吃了我的奶酪'.format(name))
threadlocal.name = name # 把需要创建内存副本的变量设置给threadLocal
getName()
def getName():
print('myname:{}'.format(threadlocal.name))
if __name__ == '__main__':
t1 = threading.Thread(target=testFunc,args=('李白',))
t2 = threading.Thread(target=testFunc,args=('杜甫',))
t1.start()
t2.start()
8.2 线程池
import threadpool
import time
def subFunc(name,age,salary):
print('名字:{},年龄:{},收入:{}'.format(name,age,salary))
time.sleep(2)
def mainFunc():
dt1 = {'name':'tom','age':10,'salary':10000}
dt2 = {'name':'张三','age':40,'salary':3000}
dt3 = {'name':'CAT','age':3,'salary':20000}
dt4 = {'name':'李白','age':30,'salary':500}
dts = [(None,dt1),(None,dt2),(None,dt3),(None,dt4)]
pool = threadpool.ThreadPool(3)
# 传参方式:[(list,dict),(list,dict),...]
reqList = threadpool.makeRequests(subFunc,dts)
[pool.putRequest(req) for req in reqList]
pool.wait()
print('------------')
if __name__ == '__main__':
mainFunc()
9、协程
协程,又称微线程。
9.1 实现方式
一、python 2.x时,使用 yield 来实现协程
二、python 3.x 使用 asyncio 标准库实现
1)python3.4 asynico + yield form
异步操作,需要在coroutine中通过yield from完成。
2)python3.5 asynico + await
异步操作,需要在coroutine中通过yield from完成。
三、第三方实现 gevent
四、aiohttp
await
import asyncio
# IO 操作函数
async def readFile(i):
k = 0
with open('img.txt', mode='r', encoding='utf8') as f:
for _ in f:
k += 1
# 包含耗时的 IO 操作的函数
async def one(i):
await asyncio.gather(readFile(i))
return 100 + i # 不指定 return,则返回 None
gevent
from gevent import monkey; monkey.patch_socket()
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(), i)
g1 = gevent.spawn(f, 3)
g2 = gevent.spawn(f, 2)
g3 = gevent.spawn(f, 4)
g1.join()
g2.join()
g3.join()
9.2 协程优势
和多线程比,协程有何优势?
1)协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
2)协程不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程就是一个线程,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
结:因为协程就是一个线程,它不需要多线程的锁机制,也不需要进行频繁的线程切换,所以协程的执行效率极高。
10、nginx
Nginx 是一个高性能的 web 和反向代理服务器,也可作为负载均衡服务器,还可以作为邮件代理服务器。
10.1 工作原理
Nginx 采用的是 master-worker 模型,一个 master 进程管理多个 worker 进程,基本的事件处理都是放在 woker 中,master 负责一些全局初始化,对请求及任务的分发收集,以及对 worker 的管理。
10.2 nginx 优点
轻量级同样起web 服务比apache占用更少内存及资源
抗并发nginx 处理请求异步非阻塞而apache 则阻塞型高并发下nginx 能保持低资源低消耗高性能
高度模块化设计编写模块相对简单
社区活跃各种高性能模块出品迅速啊
10.3 Nginx为什么性能高,占用内存少
众所周知,nginx性能高,而nginx的高性能与其架构是分不开的。在这里,我们简单粗略的介绍一下nginx的架构。
首先,nginx采用的是多进程模式,好处是什么呢?首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低风险。
Nginx是采用异步非阻塞的方式去处理请求的,什么是异步非阻塞呢?其实就是当一个线程调用出现等待的io之类的情况时,而不是阻塞在这里,而是去处理别的事情,等io准备好了,然后再去执行,具体的我就不在这里和大家描述了。
结:
1)nginx采用的是多进程模式。
2)Nginx是采用异步非阻塞的方式去处理请求的。
10.4 5、负载均衡策略
1. RR (轮询策略)
按照轮询(默认)方式进行负载,每个请求按时间顺序逐一分配到不同的后端服务器,
如果后端服务器down掉,能自动剔除。虽然这种方式简便、成本低廉。
但缺点是:可靠性低和负载分配不均衡(如服务器性能不同时)。
upstream tomcats {
server 10.1.1.107:88 max_fails=3 fail_timeout=3s weight=9;
server 10.1.1.132:80 max_fails=3 fail_timeout=3s weight=9;
}
2. 权重
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream test{
server localhost:8080 weight=9;
server localhost:8081 weight=1;
}
此时8080和8081分别占90%和10%。
3. ip_hash
上面的 2 种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,
当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,
比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,
所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,
iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,
可以解决session的问题。
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
4. fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
5. url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}
10.5 nginx 服务器进程线程配置
-
worker_processes:工作进程数
nginx默认只使用cpu的一个核,单核支持的线程数是1024,意味着超过1024就会崩。
根据需要可以自定义配置:worker_processes 4 (数字“4”为您所需要使用的核数,建议设置为等于CPU总核心数,查看CPU内核:cat /proc/cupinfo) -
worker_rlimit_nofile:
nginx默认只允许单个文件被4096个线程打开,意味着如果nginx的线程超过4096也会崩,哪怕设置CPU核数大于4个。
根据需要可以自定义配置:worker_rlimit_nofile 32768
最好与ulimit -n 的值保持一致。 -
worker_connections:单个工作进程可以允许同时建立外部连接的数量
数字越大,能同时处理的连接越多。
worker_connections解析
1.connections不是随便设置的,而是与两个指标有重要关联,一是内存,二是操作系统级别的“进程最大可打开文件数”。
2.内存:每个连接数分别对应一个read_event、一个write_event事件,一个连接数大概占用232字节,2个事件总占用96字节,那么一个连接总共占用328字节,通过数学公式可以算出100000个连接数大概会占用 31M = 100000 * 328 / 1024 / 1024,当然这只是nginx启动时,connections连接数所占用的nginx。
3.进程最大可打开文件数:进程最大可打开文件数受限于操作系统,可通过 ulimit -n 命令查询,以前是1024,现在是65535,
nginx提供了worker_rlimit_nofile指令,这是除了ulimit的一种设置可用的描述符的方式。 该指令与使用ulimit对用户的设置是同样的效果。此指令的值将覆盖ulimit的值,如:worker_rlimit_nofile 20960;
设置ulimits:ulimit -SHn 65535
11、numpy 和 pandas 区别
numpy是数值计算的扩展包,pandas是做数据处理。
- numpy
数值型,重点在于进行矩阵运算
- pandas
多数据类型,重点在于进行数据分析。
pandas 有两种主要的数据结构:Series 和 DataFrame- Series是一种类似于一维数组的对象
- DataFrame 是用于存储
表格数据
的多维数据结构,可把它看作 excel 来帮助理解。
12、分析函数、窗口函数
https://www.cnblogs.com/theonewu/p/9446882.html
oracle
-
聚合函数
SUM :该函数计算组中表达式的累积和
MIN :在一个组中的数据窗口中查找表达式的最小值
MAX :在一个组中的数据窗口中查找表达式的最大值
AVG :用于计算一个组和数据窗口内表达式的平均值。
COUNT :对一组内发生的事情进行累积计数 -
开窗函数
RANK :根据ORDER BY子句中表达式的值,从查询返回的每一行,计算它们与其它行的相对位置
DENSE_RANK :根据ORDER BY子句中表达式的值,从查询返回的每一行,计算它们与其它行的相对位置
FIRST :从DENSE_RANK返回的集合中取出排在最前面的一个值的行
LAST :从DENSE_RANK返回的集合中取出排在最后面的一个值的行
FIRST_VALUE :返回组中数据窗口的第一个值
LAST_VALUE :返回组中数据窗口的最后一个值。
LAG :可以访问结果集中的其它行而不用进行自连接
LEAD :LEAD与LAG相反,LEAD可以访问组中当前行之后的行
ROW_NUMBER:返回有序组中一行的偏移量,从而可用于按特定标准排序的行号 -
数据分析函数
STDDEV :计算当前行关于组的标准偏离
STDDEV_POP:该函数计算总体标准偏离,并返回总体变量的平方根
STDDEV_SAMP:该函数计算累积样本标准偏离,并返回总体变量的平方根
VAR_POP :该函数返回非空集合的总体变量(忽略null)
VAR_SAMP :该函数返回非空集合的样本变量(忽略null)
VARIANCE :如果表达式中行数为1,则返回0,如果表达式中行数大于1,则返回VAR_SAMP
COVAR_POP :返回一对表达式的总体协方差
COVAR_SAMP:返回一对表达式的样本协方差
CORR :返回一对表达式的相关系数
select * ,first_value(s_id) over (partition by c_id order by s_score)first_show from score;
select e.deptno,
e.empno,
e.ename,
e.sal,
sum(e.sal)over() 总收入,
sum(e.sal)over(partition by e.deptno) 部门总收入,--按部门分组求和
sum(e.sal)over(order by e.empno) 员工累计收入,--按照员工编号(empno)的排序取累计收入和
sum(e.sal)over(partition by e.deptno order by e.empno) 员工部门内累计收入,--按部门(deptno)分组,同时按员工编号(empno)排序取员工部门内累计收入和
sum(e.sal)over(partition by e.deptno order by e.empno rows between unbounded preceding and unbounded following) 部门总收入2--可指定范围,结果同上
from emp e;
select id,
sum(id) over(order by id) default_sum,
sum(id) over(order by id range between unbounded preceding and current row) range_unbound_sum, # 第1行和当前行之间的
sum(id) over(order by id rows between unbounded preceding and current row) rows_unbound_sum,
sum(id) over(order by id range between 1 preceding and 2 following) range_sum,
sum(id) over(order by id rows between 1 preceding and 2 following) rows_sum
from t;
rows表示 行,就是前n行,后n行。
而range表示的是 具体的值,比这个值小n的行,比这个值大n的行。
select *,
count(*) over(partition by groupname
order by id
rows between current row and 1 following) 当前行_后1行,
count(*) over(partition by groupname
order by id
rows between 1 preceding and current row ) 前1行_当前行,
count(*) over(partition by groupname
order by id
rows between current row and unbounded following) 当前行_最后1行,
count(*) over(partition by groupname
order by id
rows between unbounded preceding and current row) 第1行_当前行,
count(*) over(partition by groupname
order by id rows between 1 preceding and 1 following) 前1行_后1行,
count(*) over(partition by groupname
order by id
rows between unbounded preceding and 1 following) 第1行_后1行,
count(*) over(partition by groupname
order by id
rows between 1 preceding and unbounded following) 前1行_最后1行
from test
13、设计模式
1)单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。
class Singleton():
_singleton = None
def __new__(cls, *args, **kwargs):
if not cls._singleton:
cls._singleton = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._singleton
class MyCls(Singleton):
pass
a = MyCls()
b = MyCls()
2)工厂模式
工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。
class Person:
def __init__(self):
self.name = None
self.gender = None
def getName(self):
return self.name
def getGender(self):
return self.gender
class Male(Person):
def __init__(self, name):
print("Hello Mr." + name)
class Female(Person):
def __init__(self, name):
print("Hello Miss." + name)
class Factory:
def getPerson(self, name, gender):
if gender == 'M':
return Male(name)
if gender == 'F':
return Female(name)
if __name__ == '__main__':
factory = Factory()
person = factory.getPerson("Chetan", "M")
3)装饰器模式
装饰器模式通常用于扩展一个对象的功能。
import functools
def memoize(fn):
known = dict()
@functools.wraps(fn)
def memoizer(*args):
if args not in known:
known[args] = fn(*args)
return known[args]
return memoizer
@memoize
def nsum(n):
'''返回前n个数字的和'''
assert (n >= 0), 'n must be >= 0'
return 0 if n == 0 else n + nsum(n - 1)
4)观察者模式
14、迭代器和生成器
迭代器:可以用for 循环遍历的对象就是可迭代对象
生成器:一边循环一边计算的机制。
获取生成器 generator 中的元素,可以通过 next(generator) 不断获取下一个元素
生成器是生成元素的,迭代器是访问集合元素的一中方式。
15、filter/map/reduce
1)filter
filter(function or None, iterable) --> filter object
返回一个迭代器,可迭代对象元素经过操作,如果结果为 true,则返回该元素。
def getOdd(num):
return num % 2 != 0
lt = [1, 2, 3, 4, 5, 6, 7, 8]
lt2 = filter(getOdd, lt)
print(lt2) # <filter object at 0x00000207CC346BE0>
print(list(lt2)) # [1, 3, 5, 7]
def getOdd(num):
return num.isdigit()
lt2 = filter(getOdd, 'ab3c5d0')
print(list(lt2)) # ['3', '5']
lt2 = filter(None, 'ab3c5d0')
print(list(lt2)) # ['a', 'b', '3', 'c', '5', 'd', '0']
2)map
map(func, *iterables) --> map object
创建一个迭代器,使函数作用在每个可迭代对象的元素上。当最短的可迭代被耗尽时停止。
def powFunc(num):
return pow(num, 2)
lt = [1, 2, 3, 4, 5]
lt2 = map(powFunc, lt)
print(lt2) # <map object at 0x000001FBD6DBB0A0>
print(list(lt2)) # [1, 4, 9, 16, 25]
3)reduce
reduce(function, sequence[, initial]) -> value
将包含两个参数的函数累计运算应用于序列的项,从左到右,从而将序列缩减为单个值。
from functools import reduce
def sumFunc(a, b):
return a + b
lt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
lt2 = reduce(sumFunc, lt)
print(lt2) # 55
lt = ['a', 'b', 'c', 'd']
lt2 = reduce(sumFunc, lt)
print(lt2) # abcd
16、==和is
==:比较对象的值是否相等
is:比较对象的id值是否相等(内存地址是否相同)
17、init()和__new()__
new():用来创建一个类(cls)的新实例,并返回该实例 (负责实例的创建)
init():在创建实例之后才调用,用于设置对象属性及其初始值 (负责初始化工作)
call():如果类实现了这个方法,则相当于把这个类对象当作函数来使用
也就是,__new__在__init__之前被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数。
18、数据结构和算法
数据结构 是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。
算法:https://blog.csdn.net/weixin_42725107/article/details/102854120