如何應對併發 關於資料索引

2021-08-02 05:49:46 字數 3729 閱讀 1725

select * from iparea where $ip between ipstart and ipend;
在早期mysql及大部分資料庫是不支援between and 中使用索引的,據說最新版本已經提供了支援,但是最近幾年沒有從事技術,沒有測試,不知道效率如何,那麼在早期,如果資料查詢,這樣一條sql,無法使用索引,就要遍歷所有結果,這個開銷是不能忍受的,(雖然不用1秒就可以執行出結果,但是開銷依然比較大,一秒鐘可以處理的查詢最多幾十次,而我們的要求是,一秒鐘幾千次!)

那麼這個問題的特點是什麼呢,ip位址區間表並不是經常變化的,比較固定,那麼在這種情況下,其實不用資料庫都可以,乙個完全排好序的佇列放在記憶體裡,程式用二分法來查詢,每秒種處理幾千個非常輕鬆(這程式不用教了吧),當然,其實還有更極端效率的處理途徑,這裡不展開,有興趣的同學自己思考。

sql select * from

user

where area='$area'

order

by lastlogin desc limit 30;

(這個 limit 特別重要)

稍微懂一點索引的同學都應該知道,正確的索引是area+lastlogin 復合索引,那麼,我們把這個思考方式推演一下。

如果只把area當作索引會怎樣,資料庫會把符合這個area的所有結果拿出來,然後按照lastlogin排好序給你,這樣就要遍歷所有符合這個area的使用者記錄;

如果只把lastlogin作為索引會如何,我們想象,lastlogin是乙個有序的數列,資料庫會從最後一條開始往前挨條遍歷,每條都去比對area是不是符合查詢條件,直到數出30條,遍歷結束,請注意,不是全部遍歷,在這裡,如果area 是個熱門城市,比如上海,北京,可能遍歷200次左右就出結果了,效率很快,但如果是個冷門城市,可能要遍歷幾千條幾萬條結果,甚至全部資料表遍歷都湊不出符合條件的30條。這樣效率就要命了。 所以用lastlogin為索引,效率存在風險。

那麼兩個我都建立索引呢?這個mysql只會選擇乙個索引,我記得不同資料庫版本的選擇策略都不同(實戰中遇到過測試伺服器用的索引很正確,線上伺服器使用了錯誤索引,因為資料庫版本不同),所以我給不出肯定的答案,但是有一點,兩個索引沒有意義,都不是最優解。

那麼如果把lastlogin+area建立索引呢?你們設想一下,兩個字段拼在一起,作為有序數列,然後資料庫去查詢的時候,lastlogin+area,這時候area是沒用的字尾,在排序中根本體現不出他存在的意義,和單獨lastlogin索引是完全一樣的。

而area+lastlogin呢,把兩個字段拼接然後排好序後,看這條sql在這個數列中查詢的體現,所命中的完全是連續的30條,也就是資料庫只遍歷30條索引記錄即完成搜尋,效率最好。

這段有點囉嗦,如果不理解,建議多讀幾遍,理解這個思路,對理解索引的效率幫助特別大,我剛工作的時候寫sql也是瞎寫,對索引一知半解全靠蒙,有了這個概念後豁然開朗,從此對索引效率的認識精進了一大截,我看網上各種索引優化的教程,各種規律總結,其實你把這個認識達到了,那些規律基本上不用記,都淺顯的如1+1一樣。

理解如上思路,就能一併理解如下策略

a+b索引可以替代a索引,而不能替代b索引。

where key like 『keyword%』 可以用到key 索引

where key like 『%keyword%』 不能用到key索引

我很笨,所以我的理解方式都是基於中學生知識基礎的思路,如果您有更好的理解思路,也可以忽略本文。

第三個問題,如何評估sql的執行開銷

剛才提到乙個重要的概念,就是索引中遍歷的記錄越少,效率越高,遍歷的記錄越多,效率越差。 在慢查詢日誌或者explain分析中,乙個重要的指標是 affected rows,(好像也有別的叫法,不查證了,大家應該能知道我說的是什麼),這個就是索引遍歷的記錄說,我以前硬翻譯叫做影響結果集,我後來看其他人寫的資料庫文件叫索引掃瞄行數,概念是一樣的。

那麼,要強調一點,一條查詢語句,其執行開銷,在大多數情況下,與影響結果集,也就是索引掃瞄行數,呈線性相關,舉兩個常見經典資料優化的問題案例。

經典案例1,大翻頁問題

論壇社群常見,翻頁越靠後效率越低,很多論壇本身訪客到沒事,訪客不太會翻幾百頁幾千頁,但是被搜尋引擎蜘蛛抓取的時候,因為連續抓取大翻頁,導致資料庫崩潰,這案例太多了,很多站長為此鬱悶莫名,不知所措。

案例sql如下

按最新更新的板塊第一頁帖子

select * from post where boardid=$id order

by lastupd desc limit 0,30;

按最新更新的板塊第100頁帖子

select * from post where boardid=$id order

by lastupd desc limit 3000,30;

這兩個sql 看上去只有limit有區別,索引都是boardid+lastupd (不要搞錯順序,理解一下)

但第一條sql索引只掃瞄30行;第二條sql索引掃瞄了3030行,其效率是第一條sql的1/100.

搜尋引擎的蜘蛛抓取 大翻頁就是 這樣把論壇搞死的。

經典案例2,積分排行問題

比如很多小遊戲提交成績,告訴你排名全球多少名,有印象吧。

這個問題我依稀記得雲風大神吐槽過,好像曾經陌陌有一款遊戲在這裡有非常嚴重的效能問題,被他狠狠bs了一把。

案例sql如下

select

count(*) from gamescore where gameid=$gameid and score>'$score' ;

索引怎麼建?

gameid+score復合索引,順序不能錯,為什麼,按照上面說的思路,自己思考一下。

那麼這個效率怎麼評估?

看結果,如果你遊戲成績特別好,前幾名,前幾十名,你的結果就是索引掃瞄行數,(如果索引都設計錯了那就不要提了)。

如果你的遊戲成績很爛,幾萬名,幾十萬名,那麼索引掃瞄了幾萬條,幾十萬條,就效率非常低了,如果有一批人同時在提交成績,又都是這種幾萬名,幾十萬名的使用者,資料庫非崩潰不可,你再多伺服器也白搭。

所以,常見的解決方法是,積分排行只針對最靠前的使用者提供,後面只給估算或區間了。

當然,這裡有個終極方案,用redis的有序陣列結構,一勞永逸的解決這個問題,redis四種資料結構,各有所長,有興趣的可以深入研究一下,今天這裡不展開。

第四個常見問題,mysql 分析和優化的方法

剛才我說了索引掃瞄行數,或者說影響結果集,對查詢效率的影響極大,那麼有人說了,怎麼證明呢?

給大家乙個日常sql分析和自我測試的方法。

首先,你一條sql如果執行很慢,你用explain 解析一下,看看是否影響結果集很大,這是其一。

其二,對這條很慢的sql做乙個狀態拆解,在mysql中是這樣操作的。

set profiling=1;

執行問題sql;

show profile for query 1;

通常,如果這個問題sql確實是索引出了問題,也就是影響結果集,或者說索引掃瞄行數較多,那麼他的執行狀態最多的消耗就在 sending data這個狀態上,這個狀態不要被名字騙了,其實負載是在i/o,硬碟掃瞄上。

你測試的時候就可以看,影響結果集的數字,和sending data上狀態的開銷,是不是線性相關,對乙個複雜的資料表結構,匯入上百萬條記錄,然後用不同索引方式和不同sql查詢,利用 explain 和set profiling 這些操作反覆分析sql的影響結果集和開銷構成。結合我今天說的思考方式,就可以更好理解了。

如何應對高併發?

參照乙個大佬的文章,我也寫一篇高併發的文章,一下這門高階的現象,以及一些解決措施。乙個關於高併發的問題 那位大佬說 如果真的幹過高併發系統的人,面試官是絕對不會對你提出這個問題的,否則就是他太不明智了。至於為嘛這樣說呢,因為如果設計乙個高併發系統,這句話就是錯誤的了,因為在脫離了業務的系統架構中都是...

關於資料併發

當多個使用者同時更新同一資料的時候,由於更新可能導致資料的不一致性,使得程式的業務資料發生錯誤,這種情況可以稱之為併發。在ado net中,併發的處理可以通過三種方式來控制 保守式併發控制 開發式併發控制以及最後更新生效方式。注意 資料庫的併發處理並不是一成不變的,不同的業務場景對資料庫的併發要求是...

實際專案中如何應對高併發等場景

高併發相關常用的一些指標有響應時間 response time 吞吐量 throughput 每秒查詢率qps query per second 併發使用者數等。吞吐量 單位時間內處理的請求數量。qps 每秒響應請求數。在網際網路領域,這個指標和吞吐量區分的沒有這麼明顯。1.採用前後端分離的模式,前...