為什么分庫分表
單表數據量過大,會出現慢查詢,所以需要水平分表
可以把低頻、高頻的字段分開為多個表,低頻的表作為附加表,且邏輯更加清晰,性能更優
隨著系統的業務模塊的增多,放到單庫會增加其復雜度,邏輯不清晰,不好維護,所以會對業務進行微服務拆分,同時拆分數據庫
怎么分庫分表
事務
原子性(Atomicity):指事務是一個不可分割的最小工作單位,事務中的操作只有都發生和都不發生兩種情況
一致性(Consistency):事務必須使數據庫從一個一致狀態變換到另外一個一致狀態,舉一個栗子,李二給王五轉賬50元,其事務就是讓李二賬戶上減去50元,王五賬戶上加上50元;一致性是指其他事務看到的情況是要么李二還沒有給王五轉賬的狀態,要么王五已經成功接收到李二的50元轉賬。而對于李二少了50元,王五還沒加上50元這個中間狀態是不可見的。
隔離性(Isolation):一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對并發的其他事務是隔離的,并發執行的各個事務之間不能互相干擾。
持久性(Durability):一個事務一旦提交成功,它對數據庫中數據的改變將是永久性的,接下來的其他操作或故障不應對其有任何影響。
悲觀鎖,排他鎖,寫鎖
數據更新、插入、刪除都是帶鎖的。 只有獲得鎖才能更新數據,如果查詢其他也有for update 或者讀鎖,那么他的查詢也不能更新
select * from table where id=xx for update;
盡量要帶上條件,且條件一定要有索引, 避免鎖表
讀鎖,共享鎖
select ... lock in share mode;
讀鎖相互可以兼容,與寫鎖沖突,所以如果數據上了寫鎖,讀鎖就要等待。同理,如果數據上了讀鎖,寫鎖就要等待查看鎖
鎖情況 select * from information_schema.innodb_locks;
引擎整體情況 包括鎖 show engine innodb status;
索引
對于聯合索引 index(a,b,c), 5.7版本及之前遵從最左匹配原則,就是說 單純是 a和ab和abc和ac走索引,其他不走
當存在多個索引,possible keys有多個,但是使用的時候mysql會選取成本最少的那一個使用
什么字段適合加索引? where order by group by
不應該建立索引的字段規則 1.不應該在字段比較長的字段上建立索引,因為會消耗大量的空間 2.對于頻繁更新、插入的字段應該少建立索引,因為在修改和插入之后,數據庫會去維護索引,會消耗資源 3.盡量少在無用字段上建立索引【where條件中用不到的字段】 4.表記錄太少不應該創建索引 5.數據重復且分布平均的表字段不應該創建索引【選擇性太低,例如性別、狀態、真假值等字段】
通常場景,IN條件查詢走索引;
當IN多條件查詢時,例子: id in (1,2)。 如果數據量大于總數據量30%(這個數好像不準確),就會走全表掃描(暫未找到官方結論,但在Mysql版本為8.0.18中,本人驗證基本符合上述結論);
當IN是單條件,例子:id in (1) 數據量大于總數據30%時,依然走索引。
隔離級別
臟讀:事務a讀到了事務b未提交到數據
不可重復讀:事務a讀到了事務提交的數據
幻讀:事務a讀到了事務b insert的數據(第一次查詢讀條數和第二次讀不同)
級別臟讀不可重復讀幻讀Read uncommitted√v√Read committed Sql Server -- Oracle×v√Repeatable read Mysql××√Serializable×××
但是mysql的innodb通過mvcc機制避免了幻讀。
普通讀(快照讀,即普通的select)讀到的是歷史版本的數據,
當前讀(select..for update , insert , update, delete)這些因為需要修改數據,所以就不能讀 歷史數據,所以就會加鎖阻塞。
但是如果是穿插使用的話--先普通讀再當前讀,是無法避免幻讀的。
mvcc
主要實現rr rc的隔離級別。 通過undolog readview技術共同實現可重復讀、讀已提交 undolog: 事務的歷史版本鏈表,全局(多個事務共享)維護一個, 每一行有一個遞增的事務id 前一個版本的指針 和一個隱藏的rowid readview:每個事務開啟的時候,當前讀后生成一個readview。有 trx_ids(活躍-未提交的事務id) min_trx_id(trx_ids中最小) max_rtx_id(預分配的下一個trx_id) creator_trx_id (創建readview的trx_id)
匹配規則: 如果數據事務ID trx_id < min_limit_id,表明生成該版本的事務在生成Read View前,已經提交(因為事務ID是遞增的),所以該版本可以被當前事務訪問。 如果trx_id>= max_limit_id,表明生成該版本的事務在生成ReadView后才生成,所以該版本不可以被當前事務訪問。 如果 min_limit_id =<trx_id< max_limit_id,需腰分3種情況討論
(1).如果m_ids包含trx_id,則代表Read View生成時刻,這個事務還未提交,但是如果數據的trx_id等于creator_trx_id的話,表明數據是自己生成的,因此是可見的。
(2)如果m_ids包含trx_id,并且trx_id不等于creator_trx_id,則Read View生成時,事務未提交,并且不是自己生產的,所以當前事務也是看不見的;
(3).如果m_ids不包含trx_id,則說明你這個事務在Read View生成之前就已經提交了,修改的結果,當前事務是能看見的
rr: 使用第一次當前讀創建的readview rc: 每一次當前讀都更新readview
三范式
第一范式(1NF):每個列都不可以再拆分。(比如地址,如果用到城市、省份的數據的話,一定還要繼續拆分)
第二范式(2NF):在第一范式的基礎上,非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分。(在第一范式的基礎上消除非主鍵對主鍵的部分依賴, 比如成績表有學號、學生、系主任、系名、課程、分數), 其實如果學號+課程為主鍵就能確定分數,所以其他無關的字段就可以分離出去)
第三范式(3NF):在第二范式的基礎上,非主鍵列只依賴于主鍵,不依賴于其他非主鍵。(其實說白了就是面向對象編程的思想,比如:把系名、系主任拆到另一張表)
但也不一定必須滿足3范式,對于數據量大的業務其實要避免3表及以上的join操作,因為要避免沒有用到索引,而是用一張寬表記錄,查詢即可。
怎么保證acid
原子性: undolog, 保留一份事務中語句的操作日志,當執行發生錯誤時候,進行回滾,用反向邏輯執行操作語句。
持久性: redolog, 無論是redolog,還是正常當數據,都是先寫到buffer,在寫到磁盤。但是redolog是通過追加當模式寫入,即:順序寫。而數據 是隨機寫,明顯速度更慢,而且mysql是按頁即16kb的傳輸,所以更慢。采用了先持久化到redolog的方式。 innodb_flush_log_at_trx_commit = 1為 redolog同步到磁盤。如果是0,則系統每秒刷一次buffer到內存。
隔離性:寫寫操作,通過鎖。寫讀操作,mvcc。
一致性:事務到目的,上面三種特性共同保障數據最終一致性
數據庫出現慢查詢原因
硬件資源問題,如內存不足
出現高并發,查詢數量過大
沒有建立索引
sql沒有命中索引
返回很多不必要的數據
數據庫數量大
一億訂單數據如何設計數據庫,需要賣家、狀態進行查詢
水平分表
通過買家好hash (因為通過買家查詢的量是很大的)
做好映射,比如:賣家:買家列表--> 買家通過路由規則找到表 --> 再通過條件進行查詢 --> 合并
innodb myisam區別
事務
外鍵
innodb:聚簇索引 不支持fulltext 但可以通過sphinx插件支持。 myisam: 非聚簇 支持fulltext全文索引
行鎖 表鎖
存儲文件, innodb兩個:.frm(表定義) .ibd(數據和索引存儲) myisam三個: .frm .myd(數據存儲) .myi(索引存儲)
為啥不用b樹
b樹非頁子節點保存有數據,如果按照一行數據1k,不算上指針和鍵值的情況下,一個節點是16k,也就最大是16行數據, 所以3層b樹最多是 16 * 16 * 16 = 4096行,太少了,所以只能增加層高,意味著增加io次數,所以這個方案不可用
redolog和binglog有啥不同
使用場景不同:binlog主要用于備份、遷移、數據同步, redolog主要保證事務的持久性,遇到故障時候提供回滾重放操作
記錄時機不同,binglog是在commit之后再一次性記錄的,redolog是事務中執行的時候一條一條記錄的
binlog是記錄執行語句,redolog是記錄物理塊的數據變更