mysql 學習筆記(實踐篇)

實踐篇

09 | 普通索引和惟一索引

  • 查詢過程:性能幾乎無差異
  • 更新過程:普通索引 更新的目標頁不在內存中可使用到change buffer。建議使用普通索引。html

    change buffer:當須要更新一個數據頁時,若是數據頁在內存中就直接更新,而若是這個數據頁尚未在內存中的話,在不影響數據一致性的前提下,InnoDB 會將這些更新操做緩存在 change buffer 中,這樣就不須要從磁盤中讀入這個數據頁了。在下次查詢須要訪問這個數據頁的時候,將數據頁讀入內存,而後執行 change buffer 中與這個頁有關的操做。經過這種方式就能保證這個數據邏輯的正確性。
  • redo log 主要節省的是隨機寫磁盤的 IO 消耗(轉成順序寫),而 change buffer 主要節省的則是隨機讀磁盤的 IO 消耗。

10 | MySQL爲何有時候會選錯索引

  • explain 查詢語句執行狀況

  • show index 能夠查看索引基數

  • 優化器的選擇主要基於掃描行數(mysql使用採樣統計計算,非準確數字)判斷

  • analyze table t 能夠優化查詢分析

  • 索引選擇異常和處理mysql

    • force index 強行選擇一個索引(通常不須要,只有在查詢分析判斷問題時使用,基本仍是使用mysql內部優化器機制)
    • 更新語句,如使用 order by b,a 就會使用a,b索引
    • 業務溝通,刪除沒必要要的查詢索引
    • *

11 | 怎麼給字符串字段加索引?

  • 前綴索引,定義好長度,就能夠作到既節省空間,又不用額外增長太多的查詢成本。alter table SUser add index index2(email(6));
  • 前綴索引長度:創建索引時關注的是區分度,區分度越高越好。由於區分度越高,意味着重複的鍵值越少。所以,咱們能夠經過統計索引上有多少個不一樣的值來判斷要使用多長的前綴。sql

    mysql> select 
      count(distinct left(email,4))as L4,
      count(distinct left(email,5))as L5,
      count(distinct left(email,6))as L6,
      count(distinct left(email,7))as L7,
    from SUser;
  • 使用前綴索引極可能會損失區分度,因此你須要預先設定一個能夠接受的損失比例,好比 5%。而後,在返回的 L4~L7 中,找出不小於 L * 95% 的值,假設這裏 L六、L7 都知足,你就能夠選擇前綴長度爲 6。
  • 前綴索引就用不上覆蓋索引對查詢性能的優化
  • 對身份證相似的索引,若是用前綴的話,區分度過低,就不合適,解決方案有幾種。數據庫

    • 使用身份證倒序存儲,reverse()
    • 增長整形的hash字段,如crc32()
    • *

12 | 爲何個人MySQL會「抖」一下?

  • 更新主要是寫內容和日誌,更新內容會先存入內存(沒有同步的叫髒頁),等時機(4種狀況)再寫入磁盤。緩存

    1. redo log 寫滿了。這時候系統會中止全部更新操做,把 checkpoint 往前推動,redo log 留出空間能夠繼續寫
    2. 內存不足。當須要新的內存頁,而內存不夠用的時候,就要淘汰一些數據頁,空出內存給別的數據頁使用。若是淘汰的是「髒頁」,就要先將髒頁寫到磁盤。
    3. 系統空閒
    4. 系統重啓
  • InnoDb使用刷新內存機制。InnoDB 用緩衝池(buffer pool)管理內存

image.png

  • InnoDB 的刷盤速度就是要參考這兩個因素:一個是髒頁比例,一個是 redo log 寫盤速度。

image.png
image.png
image.png


13 | 爲何表數據刪掉一半,表文件大小不變?

  • 將innodb_file_per_table 設置爲 ON,表數據是單獨的文件ibd,drop table後會刪除文件,並回收空間,不然不行。
  • 記錄複用:刪除記錄的空間,符合條件的數據下次插入時候會使用
  • 數據頁複用:刪除後整個數據頁被標記爲可複用。
  • 插入數據:若是當前數據頁已滿,則會數據頁分裂,可能形成數據空洞。
  • 重建表:
    image.png

14 | count(*)這麼慢,我該怎麼辦?

  • Myisam 有一個地方專門記錄總數
  • InnoBb 由於是事物,併發等屬性,不能直接獲取,只能經過遍歷最小的那顆索引樹實現。
  • count(*)、count(主鍵 id) 和 count(1) 都表示返回知足條件的結果集的總行數;而 count(字段),則表示返回知足條件的數據行裏面,參數「字段」不爲 NULL 的總個數。
  • 儘可能使用count(*)
    • *

16 | 「order by」是怎麼工做的?

  • 全字段排序:併發

    • 須要查詢的字段 初始化 放入sort_buffer。
    • sort_buffer_size,就是 MySQL 爲排序開闢的內存(sort_buffer)的大小。若是要排序的數據量小於 sort_buffer_size,排序就在內存中完成。但若是排序數據量太大,內存放不下,則不得不利用磁盤臨時文件輔助排序。
  • rowid排序:socket

    • 設置 max_length_for_sort_data 大小,若是單行數據太大,使用rowid排序,rowid排序須要結果再回表查詢
  • mysql默認使用全字段排序,原則儘可能使用內存,儘可能少回表。

17 | 如何正確地顯示隨機消息?

  • order by rand() 使用了內存臨時表,內存臨時表排序的時候使用了 rowid 排序方法。要儘可能避免使用該方法。
  • image.png
  • 掃描行數是C+(Y1+1)+(Y2+1)+(Y3+1)
  • 進一步優化:
  • image.png

18 | 爲何這些SQL語句邏輯相同,性能卻差別巨大?

  • 索引字段作函數操做,會破壞索引值的有序性。
  • 隱式類型轉換:mysql 默認比較會把字符串轉換成數字。若是數字轉換成字符串,優化器會默認添加函數,因此破壞索引。需使用 where id=''的單引號。
  • 隱式字符編碼轉換:函數

    • mysql> select d.* from tradelog l , trade_detail d where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2;

19 | 爲何我只查一行的語句,也執行這麼慢

  • 第一類:簡單查詢長時間不返回工具

    • 等MDL鎖,等flush,等行鎖
    • show processlist
    • image.png
    • MySQL 啓動時須要設置 performance_schema=on,相比於設置爲 off 會有 10% 左右的性能損失。經過查詢 sys.schema_table_lock_waits 這張表,咱們就能夠直接找出形成阻塞的 process id,把這個鏈接用 kill 命令斷開便可。
  • 第二類:查詢慢oop

    • 慢查詢日誌
    • lock in share mode 的 SQL 語句,是當前讀,所以會直接讀到 1000001 這個結果。
    • select * from t where id=1 這個語句,是一致性讀,所以須要從 1000001 開始,依次執行 undo log,執行了 100 萬次之後,纔將 1 這個結果返回
    • *

20 | 幻讀是什麼,幻讀有什麼問題?

  • innoDB 間隙鎖,next-key lock。

22 | MySQL有哪些「飲鴆止渴」提升性能的方法?

  • 第一種方法:先處理掉那些佔着鏈接可是不工做的線程。
  • 第二種方法:減小鏈接過程的消耗。
  • 慢查詢性能問題
  • QPS 突增問題
  • 全量回歸測試工具(pt-query-digest
    • *

23 | MySQL是怎麼保證數據不丟的?

  • redo log 和 binlog 都是順序寫,磁盤的順序寫比隨機寫速度要快;* 組提交機制,能夠大幅度下降磁盤的 IOPS 消耗。
  • IO瓶頸解決方法:

    • image.png
  • 一般咱們說 MySQL 的「雙 1」配置,指的就是 sync_binlog 和 innodb_flush_log_at_trx_commit 都設置成 1。也就是說,一個事務完整提交前,須要等待兩次刷盤,一次是 redo log(prepare 階段),一次是 binlog。
  • 2,15,23章節redo log,bin log 和crash safe.

24 | MySQL是怎麼保證主備一致的?

  • 主備切換,binlog格式

    • statement:可能引發不一致
    • row:全量信息,能夠恢復全部數據。缺點,佔用空間大。
    • mixed:有風險的sql語句,會使用row格式記錄。
  • MariaDB 的flashback 工具:恢復數據誤操做。

25 | MySQL是怎麼保證高可用的?

  • 主備延遲的幾種狀況

    • 主備機器性能
    • 備庫壓力偏大(查詢等等)
    • 大事物
  • 策略

    • 可靠性優先策略
    • 可用性優先策略

31 | 誤刪數據後除了跑路,還能怎麼辦?

  • sql_safe_updates=On 更新或刪除強制帶where
  • 設置有效的全量備份點。經過binlog恢復數據
  • 權限帳號管理。

32 | 爲何還有kill不掉的語句?

  • 緣由1:更改狀態,發信號給block線程。
  • 緣由2:大查詢回滾,DDL,大事務,邏輯耗時長。
  • 解決辦法:影響系統環境

    • 增長並行線程數量 innodb_thread_concurrency
    • 減輕IO系統壓力
  • 客戶端鏈接超多表數據庫使用-A(不用-q)

33 | 我查這麼多數據,會不會把數據庫內存打爆?

  • 全表掃描是邊算邊發,經過socket receive buffer棧。
  • InnoDB全表掃描有淘汰機制,LRU.

34 | 到底可不可使用join?

  • 使用 join 語句,性能比強行拆成多個單表執行 SQL 語句的性能要好;
  • 若是使用 join 語句的話,須要讓小表(where過濾後數據量小的)作驅動表。
  • 被驅動表能用索引最好,不然使用內存判斷(Block Nested-Loop Join)
相關文章
相關標籤/搜索