mysql高級使用和技巧

文章首發於公衆號:松花皮蛋的黑板報
做者就任於京東,在穩定性保障、敏捷開發、高級JAVA、微服務架構有深刻的理解mysql

clipboard.png

1、普通索引和惟一索引
查詢上來講,普通索引查找到知足條件的記錄後會接着查找下一個記錄(innodb的數據是按頁讀寫的),判斷是否知足。然而惟一索引是查詢到了就當即返回了。因此若是你明確知道只有一條結果則應該加上limit 1算法

更新上來講,普通索引會用到charge buffer優化,將更新操做記錄在charge buffer中,不須要從磁盤中讀取數據而後再更新,當下次查詢該數據頁時再讀入內存而後執行merge相關操做,更新原數據。sql

2、前綴索引
查詢上來講,前綴索引可能會致使在索引樹上命中率變高可是原數據命中並不必定高,形成了必定的查詢浪費。另外對於索引上的信息足夠知足查詢條件的狀況下,前綴索引會多一次回表操做,總體索引則是直接返回(也就是覆蓋索引)。數據庫

可是若是提升數據的區分度,好比倒序存儲、hash處理後存儲等,使用前綴索引存儲空間更小,查詢次數也不會太差,收益可能會更高。架構

3、聯合索引
對於聯合索引來講,遵照最左前綴原則,也就是說若是隻有idx-union(type,time,value)聯合索引,單純的type或者type and time做來查詢條件也會命中這條索引,可是單純value做爲查詢條件則沒法命中。另外若是存在範圍查詢好比between等也會致使沒法命中函數

4、收縮表空間
當須要收縮表空間時,若是隻是delete數據,表文件大小是不變的,會被mysql標記爲可複用的空間,須要經過alter重建表才能釋放。固然若是是要刪除所有數據的話,首選應該是Truncate操做。微服務

5、count(*)操做
InnoDb是索引組織表,主鍵索引樹的葉子節點存的是整行數據,而普通索引樹的葉子節點是主鍵值(須要先查找k索引樹獲得ID,而後再到ID索引樹查找,也就是回表),不論是優化器查詢哪一個索引樹或者不使用索引,都須要將全部數據查出來而後累加返回,因此不推薦在innodb引擎的數據庫中頻繁執行count(*)操做。oop

6、顯示隨機信息
若是使用order by rand()實現,則須要在臨時表上進行rowid(有主鍵則是主鍵沒有則是系統生成標識行的rowid)排序操做,總體過程涉及全表掃描而後將數據放到內存臨時表再生成sort_buffer排序再從內存臨時表中取數據。若是sort_buffer_size沒法存儲數據,則須要使用磁盤文件進行分塊存儲而後再歸併排序。post

正確的方式應該是:性能

mysql> select count(*) into @C from t;
set @Y1 = floor(@C * rand());
set @Y2 = floor(@C * rand());
set @Y3 = floor(@C * rand());
select * from t limit @Y1,1; // 在應用代碼裏面取 Y一、Y二、Y3 值,拼出 SQL 後執行
select * from t limit @Y2,1;
select * from t limit @Y3,1;

7、where條件上不要使用函數
對索引字段作函數操做,可能會破壞索引值的有序性,由於b+樹中的同一層兄弟節點是有序的

8、where條件不要使用類型轉換
當字符串和數字作比較時,會將字符串轉換成數字,會觸發CAST等函數操做,觸發上一條規則

9、數據庫用錯索引時能夠強制force index
咱們知道Mysql結合掃描行數、是否使用臨時表、是否須要排序等綜合考慮選擇索引,固然就會出現用錯索引的狀況。平時咱們explain sql時顯示的預估掃描行數rows是mysql經過數據採樣,選擇這個索引其中n個數據頁,統計這些頁面的不一樣值,獲得平均值,而後乘以這個索引的頁面數,獲得基數,也就是區分度。另外還有若是回表代價過大,也可能會選錯索引。

10、join操做
join操做的過程是先遍歷表t1,而後根據從表t1取中的數據到表t2中查找知足條件的記錄,也就是說驅動表是走全表掃描,而被驅動表是走樹查找(index nested-loop join)。那麼理所固然選擇小表(過濾後)做爲驅動表效果更好。

若是被驅動表沒有可用的索引時,join算法會變爲表t1和表t2都走全表掃描放入內存中查找知足符合的記錄(block nested-loop join)。

可是若是驅動表分段,那麼被驅動表就被屢次讀,那麼就有可能把大部分熱點數據都淘汰掉了,致使」buffer poll hit rate」命中率低,其餘請求須要讀磁盤,這種狀況就很是不推薦使用join操做了。

接下來來講說經常使用的left joinright joininner join,好比這條語句Select * from t1 left join t2,能夠看出是以t1做爲驅動表,若是不能保證t1比t2表小盡可能使用inner join,優化器會自動選擇較好的那個驅動表。

11、group by使用磁盤臨時表
group by語句是統計不一樣的值出現的個數,可是每一個原數據的操做結果可能都是無序的,那麼就須要中間存儲表-臨時表記錄過程了。可是若是數據量過大,會出現先放到內存臨時表,插入一部分數據後,發現不夠用了再轉成磁盤臨時表,這種狀況咱們能夠加上sql_big_result提示優化器,直接使用磁盤文件。另外多說一點,若是結果不要求排序,最好使用order by null跳過內存臨時表的排序。

12、分庫分表
查詢表數據大小,合理分表分庫

SELECT CONCAT(table_schema,’.’,table_name) AS ‘Table Name’, CONCAT(ROUND(table_rows/1000000,2),’M’) AS ‘Number of Rows’, CONCAT(ROUND(data_length/(102410241024),2),’G’) AS ‘Data Size’, CONCAT(ROUND(index_length/(102410241024),2),’G’) AS ‘Index Size’ , CONCAT(ROUND((data_length+index_length)/(102410241024),2),’G’) AS’Total’FROM information_schema.TABLES WHERE table_schema LIKE ‘庫名’;

十3、樂觀鎖
樂觀鎖假設數據通常狀況下不會衝突,在數據提交更新的時候纔會作衝突檢測,經常使用version版本號的方法實現

select id,version,… from db where id=#{id}; update db set version=version+1,… where id=#{id} and version=#{version};

而相對的悲觀鎖則是在總體數據處理過程當中都加鎖,依賴數據庫的事務,性能較差

MySQL select…for update的Row Lock與Table Lock

十4、MySQL中的行鎖
MySQL的InnoDb引擎是行級鎖,須要注意的是,這不是對記錄進行鎖定,而是對索引進行鎖定。在UPDATEDELETE操做時,MySQL不只鎖定WHERE條件掃描過的全部索引記錄,並且會鎖定相依的健值,也就是所謂的next-key locking,如語句update liangsonghua_me_blog_post set update_time = now() where id > 10000會鎖定全部主鍵大於等於1000的全部記錄。另外咱們知道經過非主鍵查詢回表時,會先經過二級索引也就是非簇索引查找相應的葉子節點,得到行的主鍵值,而後使用主鍵去聚簇索引中查找數據行。實際上當非簇索引(non-cluster index)記錄被鎖定時,相關的的簇索引記錄也須要被鎖定才能完成相應的操做

文章來源:www.liangsonghua.me
做者介紹:京東資深工程師-梁鬆華,長期關注穩定性保障、敏捷開發、JAVA高級、微服務架構

clipboard.png

相關文章
相關標籤/搜索