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 优化几种方式

  1. 对查询进行优化避免全表扫描,首先考虑where和group by上涉及的列进行建立索引
  2. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
  3. in 和 not in 也要慎用,否则会导致全表扫描,连续值可以使用between and
  4. 查询使用模糊查询,两端使用%%,导致全表扫描
  5. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如 where num/2=100
  6. 应尽量避免在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,当前进程id4908
开始:进程编号1,当前进程id5832
开始:进程编号2,当前进程id5888
开始:进程编号3,当前进程id5404
结束:进程编号0,当前进程id4908
开始:进程编号4,当前进程id4908
结束:进程编号1,当前进程id5832
开始:进程编号5,当前进程id5832
结束:进程编号2,当前进程id5888
开始:进程编号6,当前进程id5888
结束:进程编号3,当前进程id5404
结束:进程编号4,当前进程id4908
结束:进程编号5,当前进程id5832
结束:进程编号6,当前进程id5888
主进程结束。。。。

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;
    }

	此时80808081分别占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行_最后1from 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值