mysql資料庫調優

2021-10-07 02:19:04 字數 3953 閱讀 8205

面試官一問到資料庫調優的,大家就說加索引,除了加索引大家還知道別的麼?

或者索引相關的點你全部都知道麼?聚簇索引,非聚簇索引,普通索引,唯一索引,change buffer,表鎖、行鎖、間隙鎖以及行鎖併發情況下的最大tps是多少?還有索引為啥會選擇錯誤?這些大家知道嘛?

因為商品id itemid一般都是主鍵,在size索引上肯定會有我們這個值,這個時候就不需要回主鍵表去查詢id資訊了。

由於覆蓋索引可以減少樹的搜尋次數,顯著提公升查詢效能,所以使用覆蓋索引是乙個常用的效能優化手段。

select * from itemcenter where name like '敖%' and size=22 and age = 20;
所以這個語句在搜尋索引樹的時候,只能用 「敖」,找到第乙個滿足條件的記錄id1,當然,這還不錯,總比全表掃瞄要好。

然後呢?

當然是判斷其他條件是否滿足,比如size。

在mysql 5.6之前,只能從id1開始乙個個回表,到主鍵索引上找出資料行,再對比字段值。

而mysql 5.6 引入的索引下推優化(index condition pushdown), 可以在索引遍歷過程中,對索引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數。

字首索引

我們存在郵箱作為使用者名稱的情況,每個人的郵箱都是不一樣的,那我們是不是可以在郵箱上建立索引,但是郵箱這麼長,我們怎麼去建立索引呢?

mysql是支援字首索引的,也就是說,你可以定義字串的一部分作為索引。預設地,如果你建立索引的語句不指定字首長度,那麼索引就會包含整個字串。

我們是否可以建立乙個區分度很高的字首索引,達到優化和節約空間的目的呢?

使用字首索引,定義好長度,就可以做到既節省空間,又不用額外增加太多的查詢成本。

上面說過覆蓋索引了,覆蓋索引是不需要回表的,但是字首索引,即使你的聯合索引已經包涵了相關資訊,他還是會回表,因為他不確定你到底是不是乙個完整的資訊,就算你是[email protected]乙個完整的郵箱去查詢,他還是不知道你是否是完整的,所以他需要回表去判斷一下。

下面這個也是我在阿里面試面試官問過我的,很長的字段,想做索引我們怎麼去優化他呢?

因為存在乙個磁碟占用的問題,索引選取的越長,占用的磁碟空間就越大,相同的資料頁能放下的索引值就越少,搜尋的效率也就會越低。

我當時就回答了乙個hash,把字段hash為另外乙個欄位存起來,每次校驗hash就好了,hash的索引也不大。

我們都知道只要區分度過高,都可以,那我們可以採用倒序,或者刪減字串這樣的情況去建立我們自己的區分度,不過大家需要注意的是,呼叫函式也是一次開銷喲,這點當時沒注意。

就比如本來是www.aobing@qq,com 其實前面的www.基本上是沒任何區分度的,所有人的郵箱都是這麼開頭的,你一搜一大堆出來,放在索引還浪費記憶體,你可以substring()函式擷取掉前面的,然後建立索引。

我們所有人的身份證都是區域開頭的,同區域的人很多,那怎麼做良好的區分呢?reverse()函式翻轉一下,區分度可能就高了。

這些操作都用到了函式,我就說一下函式的坑。

條件字段函式操作

日常開發過程中,大家經常對很多字段進行函式操作,如果對日期字段操作,浮點字元操作等等,大家需要注意的是,如果對字段做了函式計算,就用不上索引了,這是mysql的規定。

對索引欄位做函式操作,可能會破壞索引值的有序性,因此優化器就決定放棄走樹搜尋功能。

需要注意的是,優化器並不是要放棄使用這個索引。

這個時候大家可以用一些取巧的方法,比如 select * from tradelog where id + 1 = 10000 就走不上索引,select * from tradelog where id = 9999就可以。

隱式型別轉換

select * from t where id = 1

如果id是字元型別的,1是數字型別的,你用explain會發現走了全表掃瞄,根本用不上索引,為啥呢?

因為mysql底層會對你的比較進行轉換,相當於加了 cast( id as signed int) 這樣的乙個函式,上面說過函式會導致走不上索引。

隱式字元編碼轉換

還是一樣的問題,如果兩個表的字符集不一樣,乙個是utf8mb4,乙個是utf8,因為utf8mb4是utf8的超集,所以一旦兩個字元比較,就會轉換為utf8mb4再比較。

轉換的過程相當於加了convert(id using utf8mb4)函式,那又回到上面的問題了,用到函式就用不上索引了。

還有大家一會可能會遇到mysql突然卡頓的情況,那可能是mysqlflush了。

flush

redo log大家都知道,也就是我們對資料庫操作的日誌,他是在記憶體中的,每次操作一旦寫了redo log就會立馬返回結果,但是這個redo log總會找個時間去更新到磁碟,這個操作就是flush。

在更新之前,當記憶體資料頁跟磁碟資料頁內容不一致的時候,我們稱這個記憶體頁為「髒頁」。

記憶體資料寫入到磁碟後,記憶體和磁碟上的資料頁的內容就一致了,稱為「乾淨頁「。

那什麼時候會flush呢?

innodb的redo log寫滿了,這時候系統會停止所有更新操作,把checkpoint往前推進,redo log留出空間可以繼續寫。

系統記憶體不足,當需要新的記憶體頁,而記憶體不夠用的時候,就要淘汰一些資料頁,空出記憶體給別的資料頁使用。如果淘汰的是「髒頁」,就要先將髒頁寫到磁碟。

你一定會說,這時候難道不能直接把記憶體淘汰掉,下次需要請求的時候,從磁碟讀入資料頁,然後拿redo log出來應用不就行了?

這裡其實是從效能考慮的,如果刷髒頁一定會寫盤,就保證了每個資料頁有兩種狀態:

一種是記憶體裡存在,記憶體裡就肯定是正確的結果,直接返回;

另一種是記憶體裡沒有資料,就可以肯定資料檔案上是正確的結果,讀入記憶體後返回。這樣的效率最高。

mysql認為系統「空閒」的時候,只要有機會就刷一點「髒頁」。

mysql正常關閉,這時候,mysql會把記憶體的髒頁都flush到磁碟上,這樣下次mysql啟動的時候,就可以直接從磁碟上讀資料,啟動速度會很快。

那我們怎麼做才能把握flush的時機呢?

innodb刷髒頁控制策略,我們每個電腦主機的io能力是不一樣的,你要正確地告訴innodb所在主機的io能力,這樣innodb才能知道需要全力刷髒頁的時候,可以刷多快。

這就要用到innodb_io_capacity這個引數了,它會告訴innodb你的磁碟能力,這個值建議設定成磁碟的iops,磁碟的iops可以通過fio這個工具來測試。

正確地設定innodb_io_capacity引數,可以有效的解決這個問題。

這中間有個有意思的點,刷髒頁的時候,旁邊如果也是髒頁,會一起刷掉的,並且如果周圍還有髒頁,這個連帶責任制會一直蔓延,這種情況其實在機械硬碟時代比較好,一次io就解決了所有問題,

但是現在都是固態硬碟了,innodb_flush_neighbors=0這個引數可以不產生連帶制,在mysql 8.0中,innodb_flush_neighbors引數的預設值已經是0了。

資料參考:《mysql實戰》、《高效能mysql》、《丁奇mysql47講》

mysql資料庫調優

mysql資料庫調優知識分享 在進行資料庫調優時,應從以下三方面進行考慮 一 如何提高mysql快取命中率 一是在配置時,客戶端與伺服器端要使用相同的字符集而不是相容 二是在客戶端,要固化查詢的語句,從而可提高應用系統的查詢效率 三是提高記憶體中快取的配置,不過使用者的併發數越多,這個設定的效果會越...

mysql 資料庫調優

1.在sql語句查詢時,盡量不使用select 進去全表查詢,首先要考慮在where及order by 語句上的列上增加索引,一定經常需要進行檢索的字段上建立索引,但是需要注意的是乙個表的索引數最好不要超過6個,要考慮在一些不常用的字段上加索引是否有必要,索引太多反而會失去加索引的效果 同時也會降低...

MySQL資料庫調優

1 全部採用64位版本 64mysql 2 選擇穩定核心 權衡穩定,效能,功能 3 調整系統預設配置引數 例如tcp ip堆疊連線數 檔案控制代碼數 程序個數 vim etc sysctl.conf net.ipv4.ip local port range 32768 61000 vim etc s...