MySQL學習筆記2.0

1.主備延遲

來源:

  • 有些部署條件下,備庫所在機器的性能要比主庫所在的機器性能差。
  • 備庫的壓力大。
  • 大事務。

由於主備延遲的存在,所以在主備切換的時候,就相應的有不同的策略:可靠性優先策略和可用性優先策略。

2.讀寫分離

    客戶端直連方案,因爲少了一層 proxy 轉發,所以查詢性能稍微好一點兒,並且整體架構簡單,排查問題更方便。但是這種方案,由於要了解後端部署細節,所以在出現主備切換、庫遷移等操作的時候,客戶端都會感知到,並且需要調整數據庫連接信息。
    帶 proxy 的架構,對客戶端比較友好。客戶端不需要關注後端細節,連接維護、後端信息維護等工作,都是由 proxy 完成的。但這樣的話,對後端維護團隊的要求會更高。而且,proxy 也需要有高可用架構。因此,帶 proxy 架構的整體就相對比較複雜。

3.數據恢復

不同情況:
1.使用 delete 語句誤刪數據行;

    Flashback 恢復數據的原理,是修改 binlog 的內容,拿回原庫重放。而能夠使用這個方案的前提是,需要確保 binlog_format=row 和 binlog_row_image=FULL。
具體恢復數據時,對單個事務做如下處理:
    對於 insert 語句,對應的 binlog event 類型是 Write_rows event,把它改成 Delete_rows event 即可;
    對於 delete 語句,也是將 Delete_rows event 改爲 Write_rows event;
    如果是 Update_rows 的話,binlog 裏面記錄了數據行修改前和修改後的值,對調這兩行的位置即可。

2.使用 drop table 或者 truncate table 語句誤刪數據表;
3.使用 drop database 語句誤刪數據庫;
    需要使用全量備份,加增量日誌的方式。這個方案要求線上有定期的全量備份,並且實時備份 binlog。

4.使用 rm 命令誤刪整個 MySQL 實例。
    系統就會開始工作,選出一個新的主庫,從而保證整個集羣的正常工作。

4.大數據量查詢

    由於 MySQL 採用的是邊算邊發的邏輯,因此對於數據量很大的查詢結果來說,不會在 server 端保存完整的結果集。所以,如果客戶端讀結果不及時,會堵住 MySQL 的查詢過程,但是不會把內存打爆。
    而對於 InnoDB 引擎內部,由於有淘汰策略,大查詢也不會導致內存暴漲。並且,由於 InnoDB 對 LRU 算法做了改進,冷數據的全表掃描,對 Buffer Pool 的影響也能做到可控。

5.連接

    在join 語句執行過程中,驅動表是走全表掃描,而被驅動表是走樹搜索。如果可以使用被驅動表的索引,join 語句還是有其優勢的;不能使用被驅動表的索引,這樣的語句就儘量不要使用join;在使用 join 的時候,應該讓小表做驅動表。

    在決定哪個表做驅動表的時候,應該是兩個表按照各自的條件過濾,過濾完成之後,計算參與 join 的各個字段的總數據量,數據量小的那個表,就是“小表”,應該作爲驅動表。

6.臨時表

臨時表在使用上有以下幾個特點:

  • 建表語法是 create temporary table …。
  • 一個臨時表只能被創建它的 session 訪問,對其他線程不可見。
  • 臨時表可以與普通表同名。
  • session 內有同名的臨時表和普通表的時候,show create 語句,以及增刪改查語句訪問的是臨時表。
  • show tables 命令不顯示臨時表。由於臨時表只能被創建它的 session 訪問,所以在這個 session 結束的時候,會自動刪除臨時表。

7.group by

    1.如果對 group by 語句的結果沒有排序要求,要在語句後面加 order by null;
    2.儘量讓 group by 過程用上表的索引,確認方法是 explain 結果裏沒有 Using temporary 和 Using filesort;
    3.如果 group by 需要統計的數據量不大,儘量只使用內存臨時表;也可以通過適當調大 tmp_table_size 參數,來避免用到磁盤臨時表;
    4.如果數據量實在太大,使用 SQL_BIG_RESULT 這個提示,來告訴優化器直接使用排序算法得到 group by 的結果。

8.Memory 引擎

InnoDB 和 Memory 引擎的數據組織方式是不同的:

  • InnoDB 引擎把數據放在主鍵索引上,其他索引上保存的是主鍵 id。這種方式,我們稱之爲索引組織表(Index Organizied Table)。
  • 而 Memory 引擎採用的是把數據單獨存放,索引上保存數據位置的數據組織形式,我們稱之爲堆組織表(Heap Organizied Table)。

從中可以看出,這兩個引擎的一些典型不同:

  • InnoDB 表的數據總是有序存放的,而內存表的數據就是按照寫入順序存放的;
  • 當數據文件有空洞的時候,InnoDB 表在插入新數據的時候,爲了保證數據有序性,只能在固定的位置寫入新值,而內存表找到空位就可以插入新值;
  • 數據位置發生變化的時候,InnoDB 表只需要修改主鍵索引,而內存表需要修改所有索引;
  • InnoDB 表用主鍵索引查詢時需要走一次索引查找,用普通索引查詢的時候,需要走兩次索引查找。而內存表沒有這個區別,所有索引的“地位”都是相同的。InnoDB 支持變長數據類型,不同記錄的長度可能不同;
  • 內存表不支持 Blob 和 Text 字段,並且即使定義了 varchar(N),實際也當作 char(N),也就是固定長度字符串來存儲,因此內存表的每行數據長度相同。

9.自增值不連續

在 MySQL 裏面,如果字段 id 被定義爲 AUTO_INCREMENT,在插入一行數據的時候,自增值的行爲如下:

  • 如果插入數據時 id 字段指定爲 null 或未指定值,那麼就把這個表當前的 AUTO_INCREMENT 值填到自增字段;
  • 如果插入數據時 id 字段指定了具體的值,就直接使用語句裏指定的值。根據要插入的值和當前自增值的大小關係,自增值的變更結果也會有所不同。

假設,某次要插入的值是 X,當前的自增值是 Y。如果 X插入的值是 X,當前的自增值是 Y。如果X<Y,那麼這個表的自增值不變;如果X≥Y,就需要把當前自增值修改爲新的自增值。

唯一鍵衝突是導致自增主鍵 id 不連續的第一種原因。事務回滾就是第二種原因。

10.特殊情況下的insert語句

     insert … select 是很常見的在兩個表之間拷貝數據的方法。在可重複讀隔離級別下,這個語句會給 select 的表裏掃描到的記錄和間隙加讀鎖。而如果 insert 和 select 的對象是同一個表,則有可能會造成循環寫入。這種情況下,需要引入用戶臨時表來做優化。insert 語句如果出現唯一鍵衝突,會在衝突的唯一值上加共享的 next-key lock(S 鎖)。因此,碰到由於唯一鍵約束導致報錯後,要儘快提交或回滾事務,避免加鎖時間過長。

11.複製表

  • 物理拷貝的方式速度最快,尤其對於大表拷貝來說是最快的方法。如果出現誤刪表的情況,用備份恢復出誤刪之前的臨時庫,然後再把臨時庫中的表拷貝到生產庫上,是恢復數據最快的方法。但是,這種方法的使用也有一定的侷限性:必須是全表拷貝,不能只拷貝部分數據;需要到服務器上拷貝數據,在用戶無法登錄數據庫主機的場景下無法使用;由於是通過拷貝物理文件實現的,源表和目標表都是使用 InnoDB 引擎時才能使用。
  • 用 mysqldump 生成包含 INSERT 語句文件的方法,可以在 where 參數增加過濾條件,來實現只導出部分數據。這個方式的不足之一是,不能使用 join 這種比較複雜的 where 條件寫法。
  • 用 select … into outfile 的方法是最靈活的,支持所有的 SQL 寫法。但,這個方法的缺點之一就是,每次只能導出一張表的數據,而且表結構也需要另外的語句單獨備份。

12.分區表

    分區表跟用戶分表比起來,有兩個繞不開的問題:一個是第一次訪問的時候需要訪問所有分區,另一個是共用 MDL 鎖。因此,如果要使用分區表,就不要創建太多的分區。
    有兩個問題需要注意:分區並不是越細越好。實際上,單表或者單分區的數據一千萬行,只要沒有特別大的索引,對於現在的硬件能力來說都已經是小表了。分區也不要提前預留太多,在使用之前預先創建即可。比如,如果是按月分區,每年年底時再把下一年度的 12 個新分區創建上即可。對於沒有數據的歷史分區,要及時的 drop 掉。至於分區表的其他問題,比如查詢需要跨多個分區取數據,查詢性能就會比較慢,基本上就不是分區表本身的問題,而是數據量的問題或者說是使用方式的問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章