普通索引和唯一索引,應該怎麼選擇?
select id from T where k=5
查詢過程(差別不大)
通過普通索引的查詢過程:查找到k=5記錄,接着查找下一條記錄直到不滿足條件
通過唯一索引的查詢過程:查找到k=5記錄後直接返回
由於查詢過程是把整個數據頁(默認16kb)讀入內存,普通索引會多一次指針尋找和計算,如果剛好記錄在數據頁最後,則要多讀取一個數據頁,而這影響微乎其微
更新過程(寫多讀少的表建議使用普通索引)
通過普通索引的更新過程:當數據在內存中則直接更新;如果不在內存中,則將更新寫入change buffer(在從數據庫讀取數據後,會執行meige操作,將change buffer的更新作用到數據上,這樣才能得到一致的數據)
通過唯一索引的更新過程:當數據在內存中則直接更新;如果不在內存中,由於要判斷數據是否唯一,也需要將數據頁讀入內存中,既然數據頁都讀入內存中了,直接更新就好,不需要使用change buffer
change buffer減少了隨機磁盤訪問,性能提升明顯
對於寫多讀少的系統,更新寫入change buffer不會立即觸發merge,對性能提升
對於寫少讀多的系統,更新寫入change buffer後馬上及觸發merge,反而影響性能
注意redo log 和 change buffer的區別
redo log減少隨機寫磁盤的操作(WAL,先寫日誌有空再寫入磁盤)
change buffer減少隨機讀磁盤的操作(更新的時候不讀數據)
MySQL爲什麼有時候會選錯索引?
索引上不同的值越多,區分度就越大
當MySQL選錯索引時,可以用force index(索引名)強制使用索引
由於索引統計信息不準確導致的問題,可以用 analyze table 來解決
怎麼給字符串字段加索引?
完整索引
如果字段較長的話,比較佔空間
前綴索引
節省空間
增加掃描次數且無法使用覆蓋索引(每次都要回表判斷條件是否符合)
倒序存儲
對於身份證這種前綴區分度不夠的字段,可以使用倒序取後6位的方式設置索引,查詢時使用如下語句
select field_list from t where id_card = reverse('input_id_card_string');
不支持範圍查詢、額外CPU消耗(reverse函數)
hash字段
額外增加一個hash字段作爲索引
不支持範圍查詢
爲什麼我的MySQL會“抖”一下?
當內存數據頁跟磁盤數據頁內容不一致的時候,我們稱這個內存頁爲“髒頁”。
內存數據寫入到磁盤後,內存和磁盤上的數據頁的內容就一致了,稱爲“乾淨頁”。
平時執行很快的更新操作,其實就是在寫內存和日誌,而 MySQL 偶爾“抖”一下的那個瞬間,可能就是在刷髒頁(flush)
以下幾種情況刷髒頁
- redo log寫滿了
- 內存不足
- 系統空閒時
- MySQL正常關閉
通過innodb_io_capacity控制innodb刷髒頁的速度
innode_flush_neighbors參數,控制刷髒頁時是否把鄰近的髒頁也順便一起刷了(1是,0否),8.0版本中默認0
如果是固態硬盤,建議設置爲0