# 一 什么是进程 进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。 单核+多道,实现多个进程的并发执行 # 二 进程与程序的区别 程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。 须要强调的是:同一个程序执行两次,那也是两个进程,好比打开暴风影音,虽然都是同一个软件,可是能够播放两个视频 # 三 并发与并行 一 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就能够实现并发,(并行也属于并发) 二 并行:同时运行,只有具有多个cpu才能实现并行 # 四 同步\异步and阻塞\非阻塞(重点) 同步:所谓同步,就是在发出一个功能调用时,在没有获得结果以前,该调用就不会返回。按照这个定义,其实绝大多数函数都是同步调用。可是通常而言,咱们在说同步、异步的时候,特指那些须要其余部件协做或者须要必定时间完成的任务。 异步:异步的概念和同步相对。当一个异步功能调用发出后,调用者不能马上获得结果。当该异步功能完成后,经过状态、通知或回调来通知调用者。若是异步功能用状态来通知,那么调用者就须要每隔必定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这实际上是一 种很严重的错误)。若是是使用通知的方式,效率则很高,由于异步功能几乎不须要作额外的操做。至于回调函数,其实和通知没太多区别。 阻塞:阻塞调用是指调用结果返回以前,当前线程会被挂起(如遇到io操做)。函数只有在获得结果以后才会将阻塞的线程激活。有人也许会把阻塞调用和同步调用等同起来,实际上他是不一样的。对于同步调用来讲,不少时候当前线程仍是激活的,只是从逻辑上当前函数没有返回而已。 #举例: #1. 同步调用:apply一个累计1亿次的任务,该调用会一直等待,直到任务返回结果为止,但并未阻塞住(即使是被抢走cpu的执行权限,那也是处于就绪态); #2. 阻塞调用:当socket工做在阻塞模式的时候,若是没有数据的状况下调用recv函数,则当前线程就会被挂起,直到有数据为止。 非阻塞:非阻塞和阻塞的概念相对应,指在不能马上获得结果以前也会马上返回,同时该函数不会阻塞当前线程。 小结:1. 同步与异步针对的是函数/任务的调用方式:同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而进程继续处于激活状态。而异步状况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候经过状态、通知、事件等方式通知进程任务完成。 2. 阻塞与非阻塞针对的是进程或线程:阻塞是当请求不能知足的时候就将进程挂起,而非阻塞则不会阻塞当前进程 # 五 进程的建立(了解) # 六 进程的终止(了解) 1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess) 2. 出错退出(自愿,python a.py中a.py不存在) 3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,能够捕捉异常,try...except...) 4. 被其余进程杀死(非自愿,如kill -9) # 七 进程的层次结构 不管UNIX仍是windows,进程只有一个父进程,不一样的是: 1. 在UNIX中全部的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的全部成员。 2. 在windows中,没有进程层次的概念,全部的进程都是地位相同的,惟一相似于进程层次的暗示,是在建立进程时,父进程获得一个特别的令牌(称为句柄),该句柄能够用来控制子进程,可是父进程有权把该句柄传给其余子进程,这样就没有层次了。 # 八 进程的状态 其实在两种状况下会致使一个进程在逻辑上不能运行, 1. 进程挂起是自身缘由,遇到I/O阻塞,便要让出CPU让其余进程去执行,这样保证CPU一直在工做 2. 与进程无关,是操做系统层面,可能会由于一个进程占用时间过多,或者优先级等缘由,而调用其余的进程去使用CPU。 于是一个进程由三种状态: 1.进程为等待输入而阻塞 2.调度程序选择另一个程序 3.调度程序选择这个进程 4.出现有效输入 # 九 进程并发的实现(了解)
# 一 multiprocessing模块介绍 multiprocessing模块用来开启子进程,并在子进程中执行咱们定制的任务(好比函数),该模块与多线程模块threading的编程接口相似 multiprocessing模块的功能众多:支持子进程、通讯和共享数据、执行不一样形式的同步,提供了Process、Queue、Pipe、Lock等组件 须要再次强调的一点是:与线程不一样,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。 # 二 Process类的介绍 Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化获得的对象,表示一个子进程中的任务(还没有启动) 强调: 1. 须要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号 参数介绍: group参数未使用,值始终为None target表示调用对象,即子进程要执行的任务 args表示调用对象的位置参数元组,args=(1,2,'egon',) kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} name为子进程的名称 方法介绍: p.start():启动进程,并调用该子进程中的p.run() p.run():进程启动时运行的方法,正是它去调用target指定的函数,咱们自定义类的类中必定要实现该方法 p.terminate():强制终止进程p,不会进行任何清理操做,若是p建立了子进程,该子进程就成了僵尸进程,使用该方法须要特别当心这种状况。若是p还保存了一个锁那么也将不会被释放,进而致使死锁 p.is_alive():若是p仍然运行,返回True p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,须要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程 属性介绍: p.daemon:默认值为False,若是设为True,表明p为后台运行的守护进程,当p的父进程终止时,p也随之终止,而且设定为True后,p不能建立本身的新进程,必须在p.start()以前设置 p.name:进程的名称 p.pid:进程的pid p.exitcode:进程在运行时为None、若是为–N,表示被信号N结束(了解便可) p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络链接的底层进程间通讯提供安全性,这类链接只有在具备相同的身份验证键时才能成功(了解便可) # 三 Process类的使用 建立并开启子进程的两种方式 - 开进程的方法一: import time import random from multiprocessing import Process def piao(name): print('%s piaoing' %name) time.sleep(random.randrange(1,5)) print('%s piao end' %name) p1=Process(target=piao,args=('egon',)) #必须加,号 p2=Process(target=piao,args=('alex',)) p3=Process(target=piao,args=('wupeqi',)) p4=Process(target=piao,args=('yuanhao',)) p1.start() p2.start() p3.start() p4.start() print('主线程') - 开进程的方法二: import time import random from multiprocessing import Process class Piao(Process): def __init__(self,name): super().__init__() self.name=name def run(self): print('%s piaoing' %self.name) time.sleep(random.randrange(1,5)) print('%s piao end' %self.name) p1=Piao('egon') p2=Piao('alex') p3=Piao('wupeiqi') p4=Piao('yuanhao') p1.start() #start会自动调用run p2.start() p3.start() p4.start() print('主线程') # 四 守护进程 # 五 进程同步(锁) - 加锁能够保证多个进程修改同一块数据时,同一时间只能有一个任务能够进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。 虽然能够用文件共享数据实现进程间通讯,但问题是: 1.效率低(共享数据基于文件,而文件是硬盘上的数据) 2.须要本身加锁处理 - 所以咱们最好找寻一种解决方案可以兼顾:一、效率高(多个进程共享一块内存的数据)二、帮咱们处理好锁问题。这就是mutiprocessing模块为咱们提供的基于消息的IPC通讯机制:队列和管道。 1 队列和管道都是将数据存放于内存中 2 队列又是基于(管道+锁)实现的,可让咱们从复杂的锁问题中解脱出来, 咱们应该尽可能避免使用共享数据,尽量使用消息传递和队列,避免处理复杂的同步和锁问题,并且在进程数目增多时,每每能够得到更好的可获展性。 # 六 队列(推荐使用) 进程彼此之间互相隔离,要实现进程间通讯(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 建立队列的类(底层就是以管道和锁定的方式实现): Queue([maxsize]):建立共享的进程队列,Queue是多进程安全的队列,可使用Queue实现多进程之间的数据传递。 maxsize是队列中容许最大项数,省略则无大小限制。 q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。若是blocked为True(默认值),而且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。若是超时,会抛出Queue.Full异常。若是blocked为False,但该Queue已满,会当即抛出Queue.Full异常。 q.get方法能够从队列读取而且删除一个元素。一样,get方法有两个可选参数:blocked和timeout。若是blocked为True(默认值),而且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。若是blocked为False,有两种状况存在,若是Queue有一个值可用,则当即返回该值,不然,若是队列为空,则当即抛出Queue.Empty异常. q.get_nowait():同q.get(False) q.put_nowait():同q.put(False) q.empty():调用此方法时q为空则返回True,该结果不可靠,好比在返回True的过程当中,若是队列中又加入了项目。 q.full():调用此方法时q已满则返回True,该结果不可靠,好比在返回True的过程当中,若是队列中的项目被取走。 q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()同样 # 七 管道 # 八 共享数据 # 九 信号量(了解) # 十 事件(了解) # 十一 进程池
线程是进程中单一连续的控制流程,是进程的一部分,一个进程至少有一个线程,多个线程能够属于同一个进程,且这些线程共享进程的内存空间,因此线程能够访问全局变量。 在python中,有两个包能够建立线程,thread与threading 加入join()方法是为了让线程能够正常结束,不然在多线程的时候可能会形成相似于僵尸进程的僵尸线程 多线程的实现,也就是同时建立多个线程,能够同时执行多个任务。 线程运行一共有三种状态,阻塞,就绪,运行中,再加上建立和终止,也就是线程一共有五种状态 阻塞:访问资源可是资源并未准备好 就绪:资源已经准备好了,等待调度 运行中:调度轮到该线程,而后运行线程代码 threading模块提供了一下集中锁机制 Lock互斥锁 互斥锁是一种独占锁,一个时刻只能有一个线程能够访问共享数据,使用须要先实例化一个锁对象,而后将锁当参数传入函数中,对不可分开的操做进行加锁便可 RLock可重入锁 Semaphore信号 Event事件 Condition条件
# process process函数形式 继承Process,实现子类 # pool 进程池,当要建立的进程数量比较多时,建议使用该方式 # queue 进程间通讯 使用process建立的进程,使用Queue() 使用进程池建立的进程通讯,使用Manager().Queue() 1.Queue.qsize(): 返回当前队列包含的消息数量 2.Queue.empty(): 若是队列为空 返回True 反之 False 3.Queue.full(): 若是队列满了返回True 反之 False 4.Queue.get(): 获取队列中一条消息 而后将其从队列中移除 可传参数 超市时长 5.Queue.get_nowait(): 至关于 Queue.get(False) 取不到值 触发异常 6.Queue.put(): 将一个值添加到数列 可传参数 超时时长 7.Queue.put_nowait():至关于 Queue.get(False) 当队列满时 报错
一 定义 一、进程 进程是具备必定独立功能的程序关于某个数据集合上的一次运行活动, 进程是系统进行资源分配和调度的一个独立单位。 每一个进程都有本身的独立内存空间, 不一样进程经过进程间通讯来通讯。 因为进程比较重量,占据独立的内存,因此上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。 二、线程 线程是进程的一个实体, 是CPU调度和分派的基本单位, 它是比进程更小的能独立运行的基本单位. 线程本身基本上不拥有系统资源, 只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈), 可是它可与同属一个进程的其余的线程共享进程所拥有的所有资源。 线程间通讯主要经过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。 三、协程 协程是一种用户态的轻量级线程,协程的调度彻底由用户控制。 协程拥有本身的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其余地方, 在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操做栈则基本没有内核切换的开销,能够不加锁的访问全局变量,因此上下文的切换很是快。 协程:本身建立出来,内部作IO监测,资源复用,IO多路复用是协程的方式之一 2、区别: 一、进程多与线程比较 线程是指进程内的一个执行单元, 也是进程内的可调度实体。线程与进程的区别: 1) 地址空间: 线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有本身独立的地址空间 2) 资源拥有: 进程是资源分配和拥有的单位, 同一个进程内的线程共享进程的资源 3) 线程是处理器调度的基本单位, 但进程不是 4) 两者都可并发执行 5) 每一个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,可是线程不可以独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制 二、协程多与线程进行比较 1) 一个线程能够多个协程,一个进程也能够单独拥有多个协程,这样python中则能使用多核CPU。 2) 线程进程都是同步机制,而协程则是异步 3) 协程能保留上一次调用时的状态,每次过程重入时,就至关于进入上一次调用的状态 # 这里举例简单的三种方式生成协程 #第一种yield: import time def work1(): for i in range(5): print('work1',i) yield time.sleep(1) def work2(): for i in range(5): print('work2',i) yield time.sleep(1) w1 = work1() w2 = work2() while True: next(w1) next(w2) #第二种: '''greenlet包''' from greenlet import greenlet import time def work1(): for i in range(5): print('work1',i) time.sleep(1) g2.switch() #遇到耗时操做,手动切换其余操做,(如今切换了g2协程) def work2(): for i in range(5): print('work2', i) time.sleep(1) g1.switch() # 建立多协程 g1 = greenlet(work1) g2 = greenlet(work2) #启动协程 g1.switch() g2.switch() #第三种: '''gevent包''' import gevent from gevent import monkey #猴子补丁 monkey.patch_all() #给全部的耗时操做打上补丁,协程自动切换 import time def work1(): for i in range(5): print('work1',i) time.sleep(1) def work2(): for i in range(5): print('work2', i) time.sleep(1) #建立多协程与 建立多进程\多线程 的过程差很少 g1 = gevent.spawn(work1) #建立协程1 g2 = gevent.spawn(work2) #建立协程2 g1.join() #等待协程操做完成 g2.join()
同步:提交一个任务以后要等待这个任务执行完毕 异步:只管提交任务,不等待这个任务执行完毕就能够作其它的事情 阻塞:例如:在socket中的这些recvfrom,recv,accept都会产生阻塞。 非阻塞:除去阻塞中的都是通常都是非阻塞。 基本分类:阻塞IO,非阻塞IO,IO多路复用,异步IO。 # IO多路复用:经过一种机制,能够监视多个描述符(socket),一旦某个描述符就绪(通常是读就绪或者写就绪),可以通知程序进行相应的读写操做。 I/O多路复用是用于提高效率,单个进程能够同时监听多个网络链接IO I/O是指Input/Output I/O多路复用,经过一种机制,能够监视多个文件描述符,一旦描述符就绪(读就绪和写就绪),能通知程序进行相应的读写操做。 I/O多路复用避免阻塞在io上,本来为多进程或多线程来接收多个链接的消息变为单进程或单线程保存多个socket的状态后轮询处理.
select维护一个文件描述符数据结构,单个进程使用有上限,一般是1024,线性扫描这个数据结构。效率低。 pool和select的区别是内部数据结构使用链表,没有这个最大限制,可是依然是线性遍历才知道哪一个设备就绪了 epool使用事件通知机制,使用回调机制提升效率。 select/pool还要从内核空间复制消息到用户空间,而epoll经过内核空间和用户空间共享一块内存来减小复制 Windows Python: 提供: select Mac Python:提供: select Linux Python: 提供: select、poll、epoll select,poll,epoll都是IO多路复用的机制,I/O多路复用就是经过一种机制,能够监视多个描述符,一旦某个描述符就绪(通常是读就绪或者写就绪),可以通知应用程序进行相应的读写操做。但select,poll,epoll本质上都是同步I/O,由于他们都须要在读写事件就绪后本身负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需本身负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。 # select # select是经过系统调用来监视一组由多个文件描述符组成的数组,经过调用select()返回结果,数组中就绪的文件描述符会被内核标记出来,而后进程就能够得到这些文件描述符,而后进行相应的读写操做 # select的实际执行过程以下: select须要提供要监控的数组,而后由用户态拷贝到内核态 内核态线性循环监控数组,每次都须要遍历整个数组 内核发现文件描述符状态符合操做结果,将其返回 # poll poll本质上与select基本相同,只不过监控的最大链接数上相较于select没有了限制,由于poll使用的数据结构是链表,而select使用的是数组,数组是要初始化长度大小的,且不能改变 poll原理 将fd列表,由用户态拷贝到内核态 内核态遍历,发现fd状态变为就绪后,返回fd列表 # epoll epoll至关因而linux内核支持的方法,而epoll主要是解决select,poll的一些缺点 1.数组长度限制 解决方案:fd上限是最大能够打开文件的数目,具体数目能够查看/proc/sys/fs/file-max。通常会和内存有关 2.须要每次轮询将数组所有拷贝到内核态 解决方案:每次注册事件的时候,会把fd拷贝到内核态,而不是每次poll的时候拷贝,这样就保证每一个fd只须要拷贝一次。 3.每次遍历都须要列表线性遍历 解决方案:再也不采用遍历的方案,给每一个fd指定一个回调函数,fd就绪时,调用回调函数,这个回调函数会把fd加入到就绪的fd列表中,因此epoll只须要遍历就绪的list便可。
GIL:又叫全局解释器锁,每一个线程在执行的过程当中都须要先获取GIL,保证同一时刻只有一个线程在运行,目的是解决多线程同时竞争程序中的全局变量而出现的线程安全问题。 多线程下每一个线程在执行的过程当中都须要先获取GIL,保证同一时刻只有一个线程在运行 即便在多核CPU中,多线程同一时刻也只有一个线程在运行,这样不只不能利用多核CPU的优点,反而因为每一个线程在多个CPU上是交替执行的,致使在不一样CPU上切换时形成资源的浪费,反而会更慢。即缘由是一个进程只存在一把gil锁,当在执行多个线程时,内部会争抢gil锁,这会形成当某一个线程没有抢到锁的时候会让cpu等待,进而不能合理利用多核cpu资源。 GIL面试题参考答案: Python语言和GIL没有什么关系。仅仅是因为历史缘由在Cpython虚拟机(解释器),难以移除GIL。 GIL:全局解释器锁。每一个线程在执行的过程都须要先获取GIL,保证同一时刻只有一个线程能够执行代码。 线程释放GIL锁的状况: 在IO操做等可能会引发阻塞的system call以前,能够暂时释放GIL,但在执行完毕后,必须从新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100。 Python使用多进程是能够利用多核的CPU资源的。 多线程爬取比单线程性能有提高,由于遇到IO阻塞会自动释放GIL锁。
# 事务 定义:所谓事务,它是一个操做序列,这些操做要么都执行,要么都不执行,它是一个不可分割的工做单位。 # ACID,是指在可靠数据库管理系统(DBMS)中,事务(transaction)所应该具备的四个特性: 原子性(Atomicity)、 一致性(Consistency)、 隔离性(Isolation)、 持久性(Durability).这是可靠数据库所应具有的几个特性.下面针对这几个特性进行逐个讲解. # 原子性:原子性是指事务是一个不可再分割的工做单位,事务中的操做要么都发生,要么都不发生。 # 一致性:一致性是指在事务开始以前和事务结束之后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。 # 隔离性:多个事务并发访问时,事务之间是隔离的,一个事务不该该影响其它事务运行效果。 并发环境中,当不一样的事务同时操纵相同的数据时,每一个事务都有各自的完整数据空间。 事务之间的相互影响有四种:脏读,不可重复读,幻读,丢失更新 1.脏读是指在一个事务处理过程里读取了另外一个未提交的事务中的数据。 2.不可重复读是指在对于数据库中的某个数据,一个事务范围内屡次查询却返回了不一样的数据值,这是因为在查询间隔,被另外一个事务修改并提交了。 3.幻读是事务非独立执行时发生的一种现象。指在一个事务内读取到了别的事务插入的数据,致使先后读取不一致。 4.丢失更新是指两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。 幻读和不可重复读都是读取了另外一条已经提交的事务(这点就脏读不一样),所不一样的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据总体(好比数据的个数) 事务隔离性的设置语句: Serializable(串行化):可避免脏读、不可重复读、虚读状况的发生。 Repeatable read(可重复读):可避免脏读、不可重复读状况的发生。 Read committed(读已提交):可避免脏读状况发生。 Read uncommitted(读未提交):最低级别,以上状况均没法保证。 # 持久性:意味着在事务完成之后,该事务所对数据库所做的更改便持久的保存在数据库之中,并不会被回滚。 事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所作的更新,若是某个事务在执行过程当中发生错误,就能够根据日志,撤销事务对数据库已作的更新,使数据库退回到执行事务前的初始状态。 数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只容许持有锁的事务能更新该数据,其余事务必须等待,直到前一个事务释放了锁,其余事务才有机会更新该数据。
# 事务 定义:所谓事务,它是一个操做序列,这些操做要么都执行,要么都不执行,它是一个不可分割的工做单位。 # 开启事务(start transaction) # 提交事务(commit) # 回滚事务(rollback)
left join student on score.student_id=student.sid
# MyISAM引擎 - MyISAM引擎,非聚簇索引(数据 和 索引结构 分开存储) 使用B+Tree做为索引结构,叶节点的data域存放的是数据记录的地址,MyISAM的索引文件仅仅保存数据记录的地址 # InnoDB引擎 - InnoDB引擎,聚簇索引(数据 和 主键索引结构存储在一块儿) InnoDB的数据文件自己就是索引文件,表数据文件自己就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,所以InnoDB表数据文件自己就是主索引 InnoDB要求表必须有主键(MyISAM能够没有),若是没有显式指定,则MySQL系统会自动选择一个能够惟一标识数据记录的列做为主键,若是不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段做为主键,这个字段长度为6个字节,类型为长整形。 第二个与MyISAM索引的不一样是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的全部辅助索引都引用主键做为data域。 myisam 表锁: 整个表给锁了 innoDB 行锁: 行内容(经常使用) # B+Tree 1.非叶子节点只存储键值信息。 2.全部叶子节点之间都有一个链指针。 3.数据记录都存放在叶子节点中。
在数据库中索引最核心的做用是:**加速查找** 索引的底层是基于B+Tree的数据结构存储的 - myisam引擎,非聚簇索引(数据 和 索引结构 分开存储) - innodb引擎,聚簇索引(数据 和 主键索引结构存储在一块儿) 常见索引: - 主键索引:加速查找、不能为空、不能重复。 + 联合主键索引 主键和联合主键索引 alter table 表名 add primary key(列名); alter table 表名 drop primary key; - 惟一索引:加速查找、不能重复。 + 联合惟一索引(只能有一个空值) 惟一和联合惟一索引 create unique index 索引名 on 表名(列名); drop unique index 索引名 on 表名; - 普通索引:加速查找。 + 联合索引 索引和联合索引 create index 索引名 on 表名(列名); drop index 索引名 on 表名;
一、数据库服务器:运行数据库管理软件的计算机 二、数据库管理软件:mysql,oracle,db2,slqserver 三、库:文件夹 四、表:文件 五、记录:事物一系列典型的特征:egon,male,18,oldgirl 六、数据:描述事物特征的符号 SQL语句: 操做文件夹(库) 增 create database db1 charset utf8; 查 show create database db1; show databases; 改 alter database db1 charset gbk; 删 drop database db1; 操做文件(表) 切换文件夹:use db1; 查看当前所在文件夹:select database(); 增 create table t1(id int,name char); 查 show create table t1; show tables; desc t1; 改 alter table t1 modify name char(6); alter table t1 change name NAME char(7); 删 drop table t1; 操做文件内容(记录) 增 insert t1(id,name) values(1,'egon1'),(2,'egon2'),(3,'egon3'); 查 select id,name from db1.t1; select * from db1.t1; 改 update db1.t1 set name='SB'; update db1.t1 set name='ALEX' where id=2; 删 delete from t1; delete from t1 where id=2; # 单表查询 select distinct 字段1,字段2,字段3 from 库.表 where 条件 group by 分组条件 having 过滤 order by 排序字段 limit n; # 连表操做 内链接:只取两张表的共同部分 select * from employee inner join department on employee.dep_id = department.id ; 左链接:在内链接的基础上保留左表的记录 select * from employee left join department on employee.dep_id = department.id ; 右链接:在内链接的基础上保留右表的记录 select * from employee right join department on employee.dep_id = department.id ; 全外链接:在内链接的基础上保留左右两表没有对应关系的记录 select * from employee full join department on employee.dep_id = department.id ; 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 ;
# mysql优化的套路 mysql是否优化过直接体现了一个程序员的功底,mysql前期的选型以及表的设计已经决定优化的上限 - 业务选型(引擎方面) innodb or myisam 如何选目前所接触到的互联网基本都是innodb(主要是锁的力度比较细MyISAM和InnoDB.note) 编码格式 utf8 or utf8mb4 作过聊天 使用utf8没法储存表情的时候就哭了 - 架构优化 主从分离(防止发生死锁,独占锁和共享锁的容易形成死锁影响效率 数据库死锁出现缘由.note) 高并发状态下写数据时同步机制过慢(多线程手动同步能够吗 no 多个表操做统一数据不行 如何解决) - 表优化 分库分表 hash 取除模仍是取余(消息的 loginc/di 分离策略 数据库分表 是取模仍是作除法.note) 动静分离(高频修改表尽量简短,更新时候反写数据比较快,不常常更新的放在一个表里,消息计数表和消息表) 不使用外键关系 (所有是逻辑类外键) 尽量不使用存储过程、触发器、视图、event(表迁移你会绝望的) NOT NULL 设立默认值 (在用django是就体会到了坑) 手机号存储为varchar(20) (+86!!!!) 设计三范式 最小单元设计 - 索引创建 索引创建太多影响写的性能 频繁更新的字段在创建索引后 会对索引树产生影响 只作简单查询,特别复杂的尝试使用es这样的组件来解决问题 最左前缀的问题abc = a + ab + abc 索引仍是降不下数据查询量 那就是结构设计问题 - 语句优化 join 字段类型不同 会全表扫描 都说select count(*)慢 其实看引擎myisam直接存了条数 select * 太耗io 插入数据 精确到字段插入 (不然后期调整模型的时候很难受) or 换成in 模糊查询别用 - 缓存 redis 作防御 防止缓存击穿 缓存雪崩,布隆过滤器兜底 最新的布谷鸟过滤器 - 数据库选型 在数据量大的时候 关系型数据和非关系的选择就比较重要 redis levedb mysql mongo
四模块
进程线程
进程通信方式
io多路复用
select poll epoll
gil
数据库acid
事务
跨表语法
mysql存储引擎
索引是什么
数据库查询python
第四模块
进程线程协程之间的定义以及区别是什么?mysql
协程:本身建立出来,内部作IO监测,资源复用,IO多路复用是协程的方式之一 知识体系
进程线程之间的通信方式有哪些?linux
共享内存 线程之间:共享, 进程之间:相互独立 Python解释器和线程之间静态数据 联想到 GIL锁
io多路复用的实现原理是什么?程序员
监测多个文件描述符FD I/O: 输入输出 计算机自己就有本身的一套I/O多路复用体系
select poll epoll 分别是什么,区别是什么?面试
模型思想
gil 是什么,为了解决什么问题redis
数据库acid,acid的定义sql
隔离级别:脏读 总结笔记
什么是事务,事务为了解决什么问题,事物的应用场景有哪些数据库
mysql存储引擎有哪些,分别又什么区别(为何要有这么多存储引擎)django
数据库类型:要知道类型,总结 引擎原理 myisam 表锁: 整个表给锁了 innoDB 行锁: 行内容(经常使用)
索引是什么(mysql的索引有哪些,为何要有索引)编程
B+tree 怎么维护,什么结构,怎么达到快速查找.
面向对象 - 封装后续慢慢理解,能应用就行