MySQL學習筆記:高級篇

1. 存儲引擎

這裏寫圖片描述

1.1 InnoDB表引擎

  • 默認事務型引擎,最重要最廣泛的存儲引擎,性能非常優秀。數據存儲在共享表空間,可以通過配置分開。對主鍵查詢的性能高於其他類型的存儲引擎。內部做了很多優化,從磁盤讀取數據時自動在內存構建hash索引,插入數據時自動構建插入緩衝區
  • 通過一些機制和工具支持真正的熱備份,支持崩潰後的安全恢復,支持行級鎖,支持外鍵

1.2 MyISAM表引擎

  • mysql5.5版本之前的默認存儲引擎 ,擁有全文索引、壓縮、空間函數。不支持事務和行級鎖支持表鎖,不支持奔潰後的安全恢復。表存儲在兩個文件,.MYD(數據文件)和.MYI(索引文件),.frm(結構文件,所有存儲引擎都有)。設計簡單,某些場景下性能很好

1.3 其他的表引擎

  • Archive、Blackhole、CVS、Memory

參考資料
mysql 存儲引擎 · Issue #28 · chengfengjie/chengfengjie.github.io

2. 索引

2.1 索引對性能的影響

  • 大大減少服務器需要掃描的數據量,幫助服務器避免排序和臨時表、將隨機I/O變順序I/O,大大提高查詢速度,降低寫的速度、佔用磁盤

2.2 索引的使用場景

  • 小表:大部分情況下全表掃描效率更高。
  • 中到大型表:索引非常有效。
  • 特大型的表:建立和使用索引的代價隨之增長,可以使用分區技術來解決

2.3 索引的類型

  • 注意
    • 一個表只能有一個主鍵索引,可以有多個唯一索引。
    • 主鍵索引一定是唯一索引,唯一索引不是主鍵索引。
    • 主鍵可以與外鍵構成參照完整性約束,防止數據不一致
類別 說明
普通索引 最基本的索引,沒有任何約束限制
唯一索引 與普通索引類似,但是具有唯一性約束
主鍵索引 特殊的唯一索引,不允許有空值
組合索引 將多個列組合在一起創建索引,可以覆蓋多個列
外鍵索引 只有InnoDB類型的表纔可以使用外鍵索引,保證數據的一致性、完整性和實現級聯操作
全文索引 MySQL自帶的全文索引只能用於MyISAM,並且只能對英文進行全文索引

2.4 MySQL索引的創建原則

  • 最適合索引的列是在where子句中的列,或連接子句中的列而不是出現在select關鍵字後的列
  • 索引列的基數越大。索引的效果越好
  • 對字符串進行索引,應該制定一個前綴長度,可以節省大量的索引空間
  • 根據情況創建複合索引,複合索引可以提高查詢效率
  • 避免創建過多索引,索引會額外佔用磁盤空間,降低寫操作效率
  • 主鍵儘可能選擇短的數據類型,可以有效減少索引的磁盤佔用提高查詢效率

2.5 MySQL索引的注意事項

  • 複合索引遵循前綴原則
  • like查詢。%不能在前,可以使用全文索引
  • column is null可以使用索引
  • 如果MySQL估計使用索引比全表掃描更慢,會放棄使用索引
  • 如果or前的條件中的列有索引,後面的沒有,索引都不會被用到
  • 列類型是字符串,查詢時一定要給值加引號,否則索引失效

3. 查詢優化

3.1 查找分析SQL查詢慢的原因

  • 記錄慢查詢日誌
    • 分析查詢日誌,不要直接打開查詢日誌進行分析,這樣比較浪費時間和精力,可以使用pt-query-digest工具進行分析
  • 使用show profile
    • set profiling=1;開啓,服務器上執行的所有語句會檢測消耗的時間,存到臨時表中(show profiles;show profiles for query 臨時表ID
  • 使用show status
    • show status 會返回一些計數器,show global status 查看服務器級別的所有計數;
    • 有時根據這些計數,可以猜測出哪些操作代價較高或者消耗時間多
  • 使用show processlist
    • 觀察是否有大量線程處於不正常的狀態
  • 使用explain
    • 分析單條SQL語句

3.2 優化查詢過程中的數據訪問

  • 原因

    • 訪問數據太多導致查詢性能下降
    • 確定應用程序是否在檢索大量超過需要的數據,可能是太多行或列
    • 確認MySQL服務器是否在分析大量不必要的數據行
  • 避免使用如下SQL語句

    • 查詢不需要額記錄,使用limit解決
    • 多表關聯返回全部列,指定A.id,B.age
    • 總是取出全部列,SELECT * 會讓優化器無法完成索引覆蓋掃描的優化
  • 注意:重複查詢相同數據,可以緩存數據,下次直接讀取緩存!

  • 是否在掃描額外的記錄?

    • 使用explain來進行,如果發現查詢需要掃描大量數據但只返回少數的行,可以通過如下技巧去優化:使用索引覆蓋掃描,把所有用的列都放到索引中,這樣存儲引擎不需要回表獲取對應行就可以返回結果
    • 改變數據庫和表的結構,修改數據表範式(冗餘)。
    • 重寫SQL語句,讓優化器可以以更優的方式執行查詢

3.3 優化長難的查詢語句

  • 一個複雜查詢還是多個簡單查詢

    • MYSQL內部每秒能掃描內存中上百萬行數據,相比之下,響應數據給客戶端就要慢得多
    • 使用儘可能少的查詢是好的,但是有時將一個大的查詢分解爲多個小的查詢時很有必要的
  • 切分查詢

    • 將一個大的查詢分爲多個小的相同的查詢
    • 一次性刪除1000萬的數據要比一次刪除一萬,暫停一會的方案更加耗損服務器開銷
  • 分解關聯查詢

    • 可以將一條關聯語句分解成多條SQL來執行
    • 讓緩存的效率更高
    • 執行單個查詢可以減少鎖的競爭
    • 在應用層做關聯可以更容易對數據庫進行拆分

3.4 優化特定類型的查詢語句

  • 優化count()查詢

    • count( * )中*會忽略所有的列,直接統計所有列數,因此不要使用count(列名)
    • MyISAM中,沒有任何where條件的count( * )非常快
    • 當有where條件,MyISAM的count統計不一定比其他表引擎快
  • 優化方案

    • 可以使用explain查詢近似值,用近似值替代count(*)
    • 增加彙總表
    • 使用緩存
  • 優化關聯查詢

    • 確定on或者using子語句的列上有索引
    • 確保group by和order by中只有一個表中的列,這樣MySQL纔有可能使用索引
  • 優化子查詢

    • 儘可能使用關聯查詢來替代,儘量少使用子查詢
  • 優化group by 和distinct

    • 這兩種查詢均可使用索引來優化,是最有效的優化方法
    • 關聯查詢中,使用標識列進行分組的效率會更高
    • 如果不需要order by,進行group by時使用order by null,MySQL不會再進行文件排序
    • with rollup超級聚合,可以挪到應用程序處理
  • 優化limit分頁

    • limit偏移量大的時候,查詢效率低
    • 可以記錄上一次查詢的最大ID,下次查詢時直接根據該ID來查詢
  • 優化UNION查詢

    • UNION ALL的效率高於UNION

4. MySQL高可擴展和高可用

4.1 分區表的原理

  • 工作原理

    • 對用戶而言,分區表是一個獨立的邏輯表,但是底層MySQL將其分成了多個物理子表,這對用戶來說是透明的,每一個分區表都會使用一個獨立的表文件。
    • 創建表時使用partition by子句定義每個分區存放的數據,執行查詢時,優化器會根據分區定義過濾那些沒有我們需要數據的分區,這樣查詢只需要所需數據在的分區即可
    • 分區的主要目的是將數據按照一個較粗的粒度分在不同的表中,這樣可以將相關的數據存放在一起,而且如果想一次性刪除整個分區的數據也很方便
  • 適用場景

    • 1、表非常大,無法全部存在內存或者只在表最後有熱點數據,其他都是歷史數據
    • 2、分區表的數據更易維護,可以對獨立的分區進行獨立的操作
    • 3、分區表的數據可以再不同的機器上,從而高效適用資源
    • 4、可以使用分區表來避免某些特殊的瓶頸
    • 5、可以備份和恢復獨立的分區
  • 限制

    • 1、一個表最多只能有1024個分區
    • 2、5.1版本中,分區表表達式必須是整數,5.5可以使用列分區
    • 3、分區字段中如果有主鍵和唯一索引列,那麼主鍵列和唯一列都必須包含進來
    • 4、分區表中無法使用外鍵約束
    • 5、需要對現有表的結構進行修改
    • 6、所有分區都必須使用相同的存儲引擎
    • 7、分區函數中可以使用的函數和表達式會有一些限制
    • 8、某些存儲引擎不支持分區
    • 9、對於MyISAM的分區表,不能使用load index into cache
    • 10、對於MyISAM表,使用分區表時需要打開更多的文件描述

4.2 分庫分表的原理

  • 工作原理

    • 通過一些 hash 算法或者工具實現將一張數據表垂直或者水平進行物理切分。
  • 適用場景

    • 單表記錄條數達到百萬或者千萬級別時
    • 解決表鎖的問題
  • 分表方式

    • 水平分割
    • 垂直分表
  • 分庫分表缺點

    • 有些分表的策略基於應用層的邏輯算法,一旦邏輯算法改變,整個分表邏輯都會改變,擴展性較差
    • 對於應用層來說,邏輯算法無疑會增加開發成本

4.2.1 水平分表

  • 定義:表很大,分割後可以降低在查詢時需要讀的數據和索引的頁數,同時也降低了索引的層數,提高查詢速度

  • 使用場景

    • 表中的數據本身就有獨立性,例如表中分別記錄各個地區的數據或者不同時期的數據,特別是有些數據常用,有些不常用,比如切分歷史數據和活躍數據
    • 需要把數據存放到多個介質上
  • 缺點

    • 給應用增加複雜度,通常查詢時需要多個表名,查詢所有數據都需要 union 操作
    • 在許多數據庫應用中,這種複雜性會超過帶來的優點,查詢時會增加讀一個索引層的磁盤次數

4.2.2 垂直分表

  • 定義:把主鍵和一些列放在一張表,然後把主鍵和另外的列放在另一張表中

  • 使用場景

    • 表中某些列常用,而另外一些列不常用
    • 可以使數據行變小,一個數據頁能存儲更多數據,查詢時減少 I/O 次數
  • 缺點

    • 管理冗餘列,查詢所有數據都需要JOIN操作

4.3 MySQL的複製原理及負載均衡

  • MySQL 主從複製工作原理
    • 在主庫上把數據更改記錄到二進制文件(即所有的寫操作都記錄到binlog)
    • 從庫將主庫的日誌複製到自己的中繼日誌
    • 從庫讀取中繼日誌中的事件,將其重放到從庫數據中,即執行了日誌中的 SQL 語句
  • 解決了哪些問題?

    • 數據分佈:隨意停止或開始複製,並在不同地理位置分佈數據備份
    • 負載均衡:降低單個服務器的壓力
    • 高可用和故障切換:幫助應用程序避免單點失敗
    • 升級測試:可以使用更高版本的 MySQL 作爲從庫
  • 思考題

    • 設定網站的用戶數量在千萬級,但是活躍用戶的數量只有1%,如何通過優化數據庫提高活躍用戶的訪問速度?
    • 答:我們可以根據用戶的活躍程度,把活躍的用戶提取出來放到另外一張表裏面,每次活躍的用戶登陸的時候就直接到活躍用戶表中進行查詢,這樣就提高了數據庫的查詢速度。

4.4 MySQL安全性

4.4.1 SQL查詢的安全方案

  • 1、使用預處理語句防SQL注入
  • 2、寫入數據庫的數據要進行特殊字符的轉義
  • 3、查詢錯誤信息不要返回給用戶,將錯誤記錄到日誌

4.4.2 MySQL的其他安全設置

  • 1、定期做數據備份
  • 2、不給查詢用戶root權限,合理分配權限
  • 3、關閉遠程訪問數據庫權限
  • 4、修改root口令,不用默認口令,使用較複雜的口令
  • 5、刪除多餘的用戶
  • 6、改變root用戶的名稱
  • 7、限制一般用戶瀏覽其他庫
  • 8、限制用戶對數據文件的訪問權限

引用資料

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