1. 程式人生 > >高效能MySQL 個人筆記

高效能MySQL 個人筆記

# 寫作目的 最近讀了《高效能MySQL_第3版(中文)》決定寫一篇專門的部落格來記錄所學所得,以及記錄自己平時的積累經驗,並傳播給大家。

# 儲存引擎 ## MyISAM 單獨存放行數資訊(count(*)不帶篩選條件時不用讀表);   支援表鎖,不支援行鎖;   不支援事務;   對於blob以及text長欄位也可以基於前500個字元加索引;   可以設定延遲更新索引;   僅有此型別支援地理空間搜尋

## InnoDB 支援表鎖和行鎖;   四個隔離級別(未提交讀(READ UNCOMMITTED),提交讀(READ COMMITTED),可重複讀(REPEATABLE READ)(預設),可序列(SERIALIZABLE),關於鎖和事務有更詳細的文件:[美團技術部落格-Innodb中的事務隔離級別和鎖的關係](https://tech.meituan.com/innodb-lock.html));   聚簇索引:資料的儲存方式,即索引和資料是一起存放的,讀取到索引的同時,資料也能一併讀出 二級索引(非主鍵索引)必須包含主鍵索引;           # 索引 ## 索引型別 >         B-Tree索引         (樹形結構,只有兩層節點,子節點之間有指向後面節點的指標):         按照左字首原則,從最左列開始查詢;         不能跳過前面的索引,即聯合索引只能從第一列開始索引;         如果從某列是按照範圍查詢,則後面的列都無法使用索引查詢,例如between     雜湊索引:         只有精確匹配索引搜有的列的查詢才有效(因為是計算hash值);         不儲存欄位值;         雜湊索引不是按照索引值排序的,所以無法用於排序;         不支援部分索引;         只支援等值索引,即=,!=,IN(),也不支援範圍查詢比如>;         雜湊非常快,除非很多衝突;         選擇性很低的列建立雜湊索引,衝突很多,效能影響極大

## 索引策略 > 1. 獨立的列,不能是表示式的一部分,也不能是函式,如column+3=4; 2. 字首索引,當索引的列很長時可以模擬hash索引,或者選取部分字元作為索引,減少索引空間,而且儘量選擇重複性低的字元,對於blob text 或者很長的varchar必須使用字首索引,缺點是無法使用字首索引order by 和group by,也無法使用字首索引做覆蓋掃描 3. 聚簇索引,不是一種索引型別,而是一種資料儲存方式,葉子頁包含了行的全部資料,但是節點頁只包含了索引列,訪問資料更快,使用覆蓋索引時可以直接使用頁節點的主鍵值,更新索引的代價很高,插入新行或者更新導致移動行時導致"頁分裂",頁分裂將導致佔用更多的磁碟空間,聚簇索引可能導致全表掃描變慢,尤其當行比較稀疏或者由於頁分裂導致資料儲存不連續時,二級索引的葉子節點包含引用行的主鍵列,且二級索引訪問需要兩次索引查詢,因為存放的是"行指標" 4. 覆蓋索引,如果一個索引包含(覆蓋)所有需要查詢的欄位的值,這個索引被稱為覆蓋索引     

# mysql schema和資料型別優化 > 1. 資料型別越小越好(載入記憶體以及儲存空間),不要用NULL,如果為NULL,mysql自身優化會很麻煩,帶來不必要的開銷 2. varchar和char,varchar更新時容易產生分裂頁的問題,varchar(10)實際需要11的儲存空間(1位元組用於儲存長度,<=255用1個位元組),varchar適用於:字串最大長度比平均長度大很多;更新少;使用UTF-8類似的複雜字符集,每個字元使用不同的位元組數儲存; 3. blob和text,當值太大時InnoDB會使用儲存指標的方式儲存,blob是二進位制資料沒有排序規則和字符集,text有字符集和排序規則,排序時只對max_sort_length做排序(或者使用ORDER BY SUBSTRING(column,length)) 4. 使用列舉代替字串,列舉實際儲存的是整數 5. 時間型別 DATETIME-儲存的是YYYYMMDDHHMMSS的整數,TIMESTAMP-儲存的是從1970年1月1日午夜來的秒數(只用4個位元組) 6. BIT 型別是字元型別 '0'=48 實際是ASII碼值;SET型別無法通過索引查詢,儲存整數,按位炒作 7. 特殊型別 低於秒精度的時間錯使用bigint,IPv4用無符號整數儲存 INET_ATON()和INET_NTOA()函式做轉換 8. double 資料型別 格式 DOUBLE(M,D)M的含義是整個數的長度,數字長度,D是精度,幾位小數

# 其他積累經驗 1. 轉換成字串時,空格會被忽略,而java中不會忽略,例如在資料庫中是 “ abc”,在select where 條件中篩選 “abc” 會被篩出來,而在Java中再去匹配則會產生不相等問題 2. where 條件中not in範圍篩選可用關聯替換表,然後關聯欄位 is null 用於等效篩選 3. 時間格式化函式 DATE_FORMAT(createtime,"%Y%m%d %H:%i:%s") 4. GROUP_CONTACT()聚合函式,分組之後連線字串 5. 設定字元區分大小寫: 字符集中_ci字尾--不區分大小寫(character ignore),_bin字尾--二進位制比對,_cs字尾--區分大小寫(character sense) 6. 查詢後插入 insert into table1(item1,item2,...) select item1,item2,... from table2 7. ORDER BY FIELD(column, 2, 0) DESC,ctime DESC 8. FIND_IN_SET(column,'value1') 9. 表關聯順序由優化器決定,並不是指定的順序,將外連結轉化成內連線 10. 沒必要返回所有的欄位 11. IN() MySQL會事先做排序,然後二分法查詢,當條目很多時用IN() 12. mysql 索引原理:使用B+樹 MyISAM 引擎使用過節點儲存地址資訊;InnoDB引擎使用節點儲存資料,葉節點包含了完整的資料記錄,因為InnoDB的資料檔案本身要按主鍵聚集,輔助索引data域儲存相應記錄主鍵的值而不是地址,用非單調的欄位作為主鍵在InnoDB中不是個好主意 13. 優化sql:最字首原則-聯合索引(a,b,c)先匹配a,再匹配b,再匹配c,但是order by和group by時失效(需要進行全欄位匹配或者前匹配。也就是=‘xxx’ 或者 like ‘xxx%’) 14. 儘量的擴充套件索引,不要新建索引,因為索引建立太多會影響插入和刪除的操作 15. 查詢where條件資料型別不匹配也無法使用索引 16. 對於like查詢,”%”不要放在前面 17. 字串與數字比較索引使用不到 18. last_insert_id()與每個連線相關,由MySQL server來維護的,由每條連線維護獨立的值,某條連線呼叫last_insert_id()獲取到的值是這條連線最近一次insert操作執行後的自增值,該值不會被其它連線的sql語句所影響。 19.事務開啟時,插入的資料不會被其他事務讀到,事務級別至少是提交讀 20.查詢資料表大小 SELECT (SUM(DATA_LENGTH)+SUM(INDEX_LENGTH))/1048576 FROM information_schema.tables WHERE TABLE_SCHEMA='database_name' AND TABLE_NAME='TABLE_NAME';