天天看點

資料庫&緩存

資料庫「MySQL」

Jdbc 連結資料庫的具體過程

  1. 加載 JDBC 驅動;
  2. 指定連接配接屬性,建立連接配接;
  3. 建立 Statement;
  4. 執行 SQL ,擷取結果集;
  5. 關閉連結;

資料庫事務特性

  • 原子性:一個事務不可分割,要麼都執行成功,要麼都不執行;
  • 一緻性:事務是将資料庫從一個一緻的狀态變為另一個一緻性的狀态,和原子性密切相關;
  • 隔離性:兩個事務之間不會互相影響;
  • 持久性:一旦事務送出之後對于資料庫的操作是永久性的;

資料庫并發存在的問題「https://blog.csdn.net/yuxin6866/article/details/52649048」

  • 髒讀:A 事務讀取了 B 事務未送出的資料;
  • 不可重複讀:在 A 事務讀取兩次之間,B 事務進行了修改送出,A 事務兩次讀取的資料内容不一緻;
  • 幻讀:在 A 事務讀取兩次之間,B 事務進行了事務新增送出,A 事務兩次讀取的資料條數不一緻;

不可重複讀和幻讀的差別

不可重複讀和幻讀的差別:從總的來看,兩者都是對資料進行了兩次查詢,但兩次查詢的結果都不一樣。但如果你從控制的角度來看, 兩者的差別就比較大,對于前者, 隻需要鎖住滿足條件的記錄,對于後者, 要鎖住滿足條件及其相近的記錄;是以對于不可重複讀需要行鎖,對于幻讀需要表鎖。
如果使用鎖機制來實作這兩種隔離級别,在可重複讀中,當 SQL 第一次讀取到資料後,就将這些資料行加鎖,其它事務無法修改這些資料,就實作了可重複讀。但這種方法卻無法鎖住 insert 的資料,是以當事務 A 先前讀取了資料,或者修改了全部資料,事務 B 還是可以 insert 資料送出,這時事務 A 就會發現莫名其妙多了一條之前沒有的資料,這就是幻讀,不能通過行鎖來避免。

資料庫隔離級别(由低到高)

  • 讀未送出(Read Uncommitted):存在髒讀、不可重複讀、幻讀;
  • 讀已送出(Read Committed):存在不可重複讀、幻讀;
  • 可重複讀(Repeatable Read):存在幻讀「MySQL 在該級别下沒有幻讀」;
  • 串行化(Serializable):安全;

MVCC

多版本并發控制機制,在各種事務隔離級别會有不同的展現。

MVCC 在 MySQL InnoDB 中的實作主要是為了提高資料庫并發性能,用更好的方式去處理讀-寫沖突,做到即使有讀-寫沖突時,也能做到讀不加鎖,非阻塞并發讀。

  • 目前讀
讀取的是記錄的最新版本,讀取時還要保證其他并發事務不能修改目前記錄,會對讀取的記錄進行加鎖「像select lock in share mode(共享鎖), select for update ; update, insert ,delete(排他鎖)」
  • 快照讀
不加鎖的 select 操作就是快照讀,即不加鎖的非阻塞讀

MVCC(多版本并發控制) 的實作

  • 3個隐式字段「目前資料行的事務 id(tax_id)、復原指針(roll_pointer)、删除标志(delete_flag)」
  • undo 日志
  • Read View「一緻性視圖」

MVCC 帶來的好處

MVCC 是一種用來解決讀-寫沖突的無鎖并發控制,也就是為事務配置設定單向增長的時間戳,為每個修改儲存一個版本,版本與事務時間戳關聯,讀操作隻讀該事務開始前的資料庫的快照。 是以 MVCC 可以為資料庫解決以下問題:

  1. 在并發寫資料庫時,保證并發讀不會阻塞寫操作,寫操作也不用阻塞讀操作,提高了資料庫并發讀寫的性能;
  2. 同時還可以解決髒讀,幻讀,不可重複讀等事務隔離問題,但不能解決更新丢失問題;

MVCC 的原理圖:

資料庫&緩存

MySQL 在可重複讀的隔離級别下解決了幻讀,如何解決的呢?

https://blog.csdn.net/ashic/article/details/53735537

索引分類

  • 組合索引
  • 單列索引
    1. 普通索引
    2. 唯一索引
    3. 主鍵索引
  • 全文索引『隻有在 MyISAM 引擎上才使用』

解釋

  • 組合索引:在表中的多個字段組合上建立的索引,隻有在查詢條件中使用了這些字段的左邊字段時,索引才會被使用,使用組合索引時遵循最左字首集合;
  • 普通索引:MySQL中基本索引類型,沒有什麼限制,允許在定義索引的列中插入重複值和空值,純粹為了查詢資料更快一點;
  • 唯一索引:索引列中的值必須是唯一的,但是允許為空值;
  • 主鍵索引:是一種特殊的唯一索引,不允許有空值;
  • 全文索引:

MySQL 索引失效的場景,以及解決辦法「https://www.jianshu.com/p/3ccca0444432」

  • 查詢條件中有 or;『使用 union all』
  • 查詢條件中有 !=;『可以改為大于和小于,分兩次查詢』
  • 查詢條件中判空(is null 或 is not null);『修改字段預設值,為 0 或空字元串』
  • like '%xyz'(組合索引中最左比對會生效);『将 xyz 倒排使用 like 'zyx%'或者直接使用 reverse 函數』
  • 對查詢的列上有運算或者函數的;『可以把計算放在等号右邊或者用 like』
  • 字元串列沒有使用單引号;『因為 SQL 會自動轉換類型,那麼就會導緻索引失效,可以加上單引号來解決』
  • 左連接配接查詢或者右連接配接查詢查詢關聯的字段編碼格式不一樣;『改編碼』
  • MySQL 估計使用全表掃描要比使用索引快;『可以分多次查詢』
  • 連接配接查詢中,按照優化器順序的驅動表不會走索引;『換驅動表』
  • 查詢中沒有用到聯合索引的第一個字段;『按最左比對規則調整 where 以及 order by 後的字段順序』

為什麼 innoDB 中非主鍵索引的葉子節點存儲的不是值,而是主鍵

  1. 保持一緻性,當資料庫表進行DML操作時,同一行記錄的頁位址會發生改變,因非主鍵索引儲存的是主鍵的值,無需進行更改;
  2. 節省存儲空間,是以會出現回表;

聯合索引使用情況

資料庫&緩存

SQL 優化的方式

  • 查詢優化:
    1. 在 where 和 order by 後面盡量使用索引,select 後面的字段隻選需要的,做到索引覆寫,不要全寫星号,可以避免回表;
    2. 在 where 後面不要進行 null 值的判斷,對于可為 null 的字段,可以設定預設值;
    3. 在 where 後面不要使用 or,可以使用 union all 代替;
    4. 不要對列進行計算,使用 like 時不要在前面加%;
    5. 在連續的字段上使用 in,如果可以用 between 代替最好;
  • 分頁查詢優化:
    1. 保證分頁的時候 id 是規律的,比如遞增,那麼在分頁的時候,可以在 where 後面帶上上次的查詢的最大 id;
    2. 如果是基于某個字段進行排序查詢非索引内的字段,可以先查出主鍵,然後使用 inner join 進行關聯查詢;「掃描整個索引并查找到沒索引的行(可能要周遊多個索引樹)的成本比掃描全表的成本更高,是以優化器放棄使用索引」
  • 索引優化:
    1. 不要在重複值比較多的列上建立索引;
    2. 不要在長字段上建索引;
  • 對于關聯 SQL 的優化:
    1. 關聯字段加索引;
    2. 盡量把小表作為驅動表放在前面,不要讓 MySQL 優化器自己去優化「MySQL 優化器也是需要時間去優化」;
  • in 和 exsits 優化:
    1. 小表驅動大表;
  • count(*) 查詢優化:
    1. 如果表特别大的話,可以在另外的表裡面記錄行數,将兩者放在同一個事務中;
    2. 使用 show table status,比如“show table status 'user' ”,效率特别高;
    3. 将資料行加載到緩存中,但是會出現資料不一緻;「不推薦」

MySQL 讀寫分離

主從架構

  1. MySQL 主從延遲的可能原因?如何避免?
  • 網絡原因、機器磁盤性能下降等
  • 避免大事務盡量拆小、讀寫分離分散讀壓力
  1. 資料庫領域有哪些鎖以及分類?

    行/表、間隙鎖、樂觀/悲觀鎖、共享/排他,讀/寫鎖

緩存「Redis」

緩存擊穿

  • 描述

    緩存擊穿是指緩存中沒有但資料庫中有的資料(一般是緩存時間到期),這時由于并發使用者特别多,同時讀緩存沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力

  • 解決辦法
    1. 設定緩存永久不過期;
    2. 根據 key 設定互斥鎖;

緩存穿透

  • 緩存穿透是指緩存和資料庫中都沒有的資料,而使用者不斷發起請求,如發起為id為“-1”的資料或id為特别大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導緻資料庫壓力過大。
    1. 接口層增加校驗,如使用者鑒權校驗,id 做基礎校驗,id <= 0的直接攔截;
    2. 使用布隆過濾器;
    3. 從緩存取不到的資料,在資料庫中也沒有取到,這時也可以将 key-value 對寫為 key-null,緩存有效時間可以設定短點,如 30 秒(設定太長會導緻正常情況也沒法使用)。這樣可以防止攻擊使用者反複用同一個 id 暴力攻擊;

緩存雪崩

  • 緩存雪崩是指緩存中資料大批量到過期時間,而查詢資料量巨大,引起資料庫壓力過大甚至 down機。和緩存擊穿不同的是, 緩存擊穿指并發查同一條資料,緩存雪崩是不同資料都過期了,很多資料都查不到進而查資料庫。
    1. 在設定緩存過期時間時,在過期時間上加上随機時間;
    2. 部分熱點資料設定永不過期;

Redis 的跳躍表「https://www.cnblogs.com/hunternet/p/11248192.html」

Redis 緩存過期政策

  1. 惰性删除:通路一個過期的 key 進行操作時,Redis 會将該 key 删除;
  2. 定期删除:由于惰性删除政策無法保證冷資料被及時删掉,是以 Redis 會定期淘汰一批已過期的 key;
  3. 主動删除:當達到最大記憶體設定值,會主動删除部分資料;

定期删除采取的方案:

​ 預設情況下 Redis 定期檢查的頻率是每秒掃描 10 次,用于定期清除過期鍵。當然此值還可以通過配置檔案進行設定,在 redis.conf 中修改配置 “hz” 值即可, 預設的值為“hz 10”。定期删除的掃描并不是周遊所有的鍵值對,這樣的話比 較費時且太消耗系統資源。Redis 伺服器采用的是随機抽取形式,每次從過期字典中,取出 20 個鍵進行過期檢測,過期字典中存儲的是所有設定了過期時間的鍵值對。如果這批随機檢查的資料中有 25% 的比例過期,那麼會再抽取 20 個 随機鍵值進行檢測和删除,并且會循環執行這個流程,直到抽取的這批資料中過 期鍵值小于 25%,此次檢測才算完成。Redis 伺服器為了保證過期删除政策不 會導緻線程卡死,會給過期掃描增加了最大執行時間為 25ms,保證每次掃描不會超過 25ms。

主動删除包含的政策如下:「預設是第一種」

  1. allkeys-lru:根據 LRU 算法删除鍵,不管資料有沒有設定逾時屬性,直到騰出足夠空間為止;
  2. allkeys-random:随機删除所有鍵,直到騰出足夠空間為止;
  3. volatile-random: 随機删除過期鍵,直到騰出足夠空間為止;
  4. volatile-ttl:根據鍵值對象的 ttl 屬性,删除最近将要過期資料。如果沒有,回退到 noeviction 政策;
  5. noeviction:不會剔除任何資料,拒絕所有寫入操作并傳回用戶端錯誤資訊,此時 Redis 隻響應讀操作。

作者:碼上猿夢

出處:http://www.cnblogs.com/daimajun/

代碼路上一隻猿,手敲轉載請聲明。有時間請關注同名微信訂閱号【碼上猿夢】,謝謝。

總是有錯誤,希望有人能直接指出我的錯誤。