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
)
- set profiling=1;開啓,服務器上執行的所有語句會檢測消耗的時間,存到臨時表中(
- 使用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、限制用戶對數據文件的訪問權限