理論:第三章:索引使用的限制條件,sql優(yōu)化有哪些,數(shù)據(jù)同步問題(緩存和數(shù)據(jù)庫),緩存優(yōu)化

索引使用的限制條件,sql優(yōu)化有哪些

    a,選取最適用的字段:在創(chuàng)建表的時(shí)候,為了獲得更好的性能,我們可以將表中字段的寬度設(shè)得盡可能小。另外一
    個(gè)提高效率的方法是在可能的情況下,應(yīng)該盡量把字段設(shè)置為NOTNULL,
    b,使用連接(JOIN)來代替子查詢(Sub-Queries)
    c,使用聯(lián)合(UNION)來代替手動(dòng)創(chuàng)建的臨時(shí)表
    d,事物:
        a)要么語句塊中每條語句都操作成功,要么都失敗。換句話說,就是可以保持?jǐn)?shù)據(jù)庫中數(shù)據(jù)的一致性和完整
    性。事物以BEGIN關(guān)鍵字開始,COMMIT關(guān)鍵字結(jié)束。在這之間的一條SQL操作失敗,那么,ROLLBACK命令就可以
    把數(shù)據(jù)庫恢復(fù)到BEGIN開始之前的狀態(tài)。
        b) 是當(dāng)多個(gè)用戶同時(shí)使用相同的數(shù)據(jù)源時(shí),它可以利用鎖定數(shù)據(jù)庫的方法來為用戶提供一種安全的訪問方
    式,這樣可以保證用戶的操作不被其它的用戶所干擾。
    e,減少表關(guān)聯(lián),加入冗余字段
    f,使用外鍵:鎖定表的方法可以維護(hù)數(shù)據(jù)的完整性,但是它卻不能保證數(shù)據(jù)的關(guān)聯(lián)性。這個(gè)時(shí)候我們就可以使用外鍵。
    g,使用索引
    h,優(yōu)化的查詢語句
    i,集群
    j,讀寫分離
    k,主從復(fù)制
    l,分表
    m,分庫
    o,適當(dāng)?shù)臅r(shí)候可以使用存儲(chǔ)過程
     
    限制:盡量用全職索引,最左前綴:查詢從索引的最左前列開始并且不跳過索引中的列;索引列上不操作,范圍之
    后全失效; 不等空值還有OR,索引影響要注意;like以通配符%開頭索引失效會(huì)變成全表掃描的操作,字符串不
    加單引號(hào)索引失效

數(shù)據(jù)同步問題(緩存和數(shù)據(jù)庫),緩存優(yōu)化

    1.降低后端負(fù)載:對于高消耗的SQL:join結(jié)果集、分組統(tǒng)計(jì)結(jié)果;對這些結(jié)果進(jìn)行緩存。
    2.加速請求響應(yīng)
    3.大量寫合并為批量寫:如計(jì)數(shù)器先redis累加再批量寫入DB
    4.超時(shí)剔除:例如expire
    5.主動(dòng)更新:開發(fā)控制生命周期(最終一致性,時(shí)間間隔比較短)
    6.緩存空對象
    7.布隆過濾器攔截
    8.命令本身的效率:例如sql優(yōu)化,命令優(yōu)化
    9.網(wǎng)絡(luò)次數(shù):減少通信次數(shù)
    10.降低接入成本:長連/連接池,NIO等。
    11.IO訪問合并
    目的:要減少緩存重建次數(shù)、數(shù)據(jù)盡可能一致、減少潛在危險(xiǎn)。
    解決方案:
    1.互斥鎖setex,setnx:
    如果 set(nx 和 ex) 結(jié)果為 true,說明此時(shí)沒有其他線程重建緩存,那么當(dāng)前線程執(zhí)行緩存構(gòu)建邏輯。
    如果 setnx(nx 和 ex) 結(jié)果為 false,說明此時(shí)已經(jīng)有其他線程正在執(zhí)行構(gòu)建緩存的工作,那么當(dāng)前線程將休
    息指定時(shí)間 ( 例如這里是 50 毫秒,取決于構(gòu)建緩存的速度 ) 后,重新執(zhí)行函數(shù),直到獲取到數(shù)據(jù)。
     
    2永遠(yuǎn)不過期:
    熱點(diǎn)key,無非是并發(fā)特別大一級(jí)重建緩存時(shí)間比較長,如果直接設(shè)置過期時(shí)間,那么時(shí)間到的時(shí)候,巨大的訪
    問量會(huì)壓迫到數(shù)據(jù)庫上,所以要給熱點(diǎn)key的val增加一個(gè)邏輯過期時(shí)間字段,并發(fā)訪問的時(shí)候,判斷這個(gè)邏輯
    字段的時(shí)間值是否大于當(dāng)前時(shí)間,大于了說明要對緩存進(jìn)行更新了,那么這個(gè)時(shí)候,依然讓所有線程訪問老的
    緩存,因?yàn)榫彺娌]有設(shè)置過期,但是另開一個(gè)線程對緩存進(jìn)行重構(gòu)。等重構(gòu)成功,即執(zhí)行了redis set操作
    之后,所有的線程就可以訪問到重構(gòu)后的緩存中的新的內(nèi)容了
     
    從緩存層面來看,確實(shí)沒有設(shè)置過期時(shí)間,所以不會(huì)出現(xiàn)熱點(diǎn) key 過期后產(chǎn)生的問題,也就是“物理”不過期。
    從功能層面來看,為每個(gè) value 設(shè)置一個(gè)邏輯過期時(shí)間,當(dāng)發(fā)現(xiàn)超過邏輯過期時(shí)間后,會(huì)使用單獨(dú)的線程去構(gòu)建緩存。
     
    一致性問題:
    1.先刪除緩存,然后在更新數(shù)據(jù)庫,如果刪除緩存失敗,那就不要更新數(shù)據(jù)庫,如果說刪除緩存成功,而更新
    數(shù)據(jù)庫失敗,那查詢的時(shí)候只是從數(shù)據(jù)庫里查了舊的數(shù)據(jù)而已,這樣就能保持?jǐn)?shù)據(jù)庫與緩存的一致性。
    2.先去緩存里看下有沒有數(shù)據(jù),如果沒有,可以先去隊(duì)列里看是否有相同數(shù)據(jù)在做更新,發(fā)現(xiàn)隊(duì)列里有一個(gè)請
    求了,那么就不要放新的操作進(jìn)去了,用一個(gè)while(true)循環(huán)去查詢緩存,循環(huán)個(gè)200MS左右再次發(fā)送到
    隊(duì)列里去,然后同步等待緩存更新完成。