模塊四 MySQL 考覈

MySQL 考覈

1.進程

# 一 什麼是進程
	進程:正在進行的一個過程或者說一個任務。而負責執行任務則是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()同樣
# 七 管道


# 八 共享數據


# 九 信號量(瞭解)


# 十 事件(瞭解)


# 十一 進程池

2.線程

線程是進程中單一連續的控制流程,是進程的一部分,一個進程至少有一個線程,多個線程能夠屬於同一個進程,且這些線程共享進程的內存空間,因此線程能夠訪問全局變量。

在python中,有兩個包能夠建立線程,thread與threading

加入join()方法是爲了讓線程能夠正常結束,不然在多線程的時候可能會形成相似於殭屍進程的殭屍線程
多線程的實現,也就是同時建立多個線程,能夠同時執行多個任務。

線程運行一共有三種狀態,阻塞,就緒,運行中,再加上建立和終止,也就是線程一共有五種狀態

阻塞:訪問資源可是資源並未準備好
就緒:資源已經準備好了,等待調度
運行中:調度輪到該線程,而後運行線程代碼

threading模塊提供了一下集中鎖機制

Lock互斥鎖
	互斥鎖是一種獨佔鎖,一個時刻只能有一個線程能夠訪問共享數據,使用須要先實例化一個鎖對象,而後將鎖當參數傳入函數中,對不可分開的操做進行加鎖便可
RLock可重入鎖
Semaphore信號
Event事件
Condition條件

3.進程通信方式

# 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()

4.io多路複用

同步:提交一個任務以後要等待這個任務執行完畢
異步:只管提交任務,不等待這個任務執行完畢就能夠作其它的事情
阻塞:例如:在socket中的這些recvfrom,recv,accept都會產生阻塞。
非阻塞:除去阻塞中的都是通常都是非阻塞。
基本分類:阻塞IO,非阻塞IO,IO多路複用,異步IO。
# IO多路複用:經過一種機制,能夠監視多個描述符(socket),一旦某個描述符就緒(通常是讀就緒或者寫就緒),可以通知程序進行相應的讀寫操做。

I/O多路複用是用於提高效率,單個進程能夠同時監聽多個網絡鏈接IO

I/O是指Input/Output

I/O多路複用,經過一種機制,能夠監視多個文件描述符,一旦描述符就緒(讀就緒和寫就緒),能通知程序進行相應的讀寫操做。

I/O多路複用避免阻塞在io上,本來爲多進程或多線程來接收多個鏈接的消息變爲單進程或單線程保存多個socket的狀態後輪詢處理.

5.select poll epoll

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便可。

6.gil

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鎖。

7.數據庫acid

# 事務
	定義:所謂事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。
    
# 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,數據庫系統)來實現的。數據庫管理系統採用日誌來保證事務的原子性、一致性和持久性。日誌記錄了事務對數據庫所作的更新,若是某個事務在執行過程當中發生錯誤,就能夠根據日誌,撤銷事務對數據庫已作的更新,使數據庫退回到執行事務前的初始狀態。

數據庫管理系統採用鎖機制來實現事務的隔離性。當多個事務同時更新數據庫中相同的數據時,只容許持有鎖的事務能更新該數據,其餘事務必須等待,直到前一個事務釋放了鎖,其餘事務纔有機會更新該數據。

8.事務

# 事務
	定義:所謂事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。
# 開啓事務(start transaction)
# 提交事務(commit)
# 回滾事務(rollback)

9.跨表語法

left join student on score.student_id=student.sid

10.mysql存儲引擎 & B+Tree

# 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.數據記錄都存放在葉子節點中。

11.索引是什麼

在數據庫中索引最核心的做用是:**加速查找**
索引的底層是基於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 表名;

12.數據庫查詢

一、數據庫服務器:運行數據庫管理軟件的計算機
二、數據庫管理軟件: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 ;

13 mysql優化的套路

# 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

14 其餘

四模塊
進程線程
進程通信方式
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 怎麼維護,什麼結構,怎麼達到快速查找.

面向對象 - 封裝後續慢慢理解,能應用就行

相關文章
相關標籤/搜索