遇到的問題 1、最初階段 系統中做了一個監控功能,用於記錄所有的請求數據,數據插入頻繁,量非常大,比如一天1000萬條。考慮到數據插入的效率,就使用記憶體KV緩存來保存。寫入過程是在接收到請求後放入到線程池中,然後線程池非同步處理後寫入。到這問題基本上沒什麼事情。 2、新的需求 後面數據保存了,就需要在 ...
遇到的問題
1、最初階段
系統中做了一個監控功能,用於記錄所有的請求數據,數據插入頻繁,量非常大,比如一天1000萬條。考慮到數據插入的效率,就使用記憶體KV緩存來保存。寫入過程是在接收到請求後放入到線程池中,然後線程池非同步處理後寫入。到這問題基本上沒什麼事情。
2、新的需求
後面數據保存了,就需要在運維繫統中可以查詢到,所以這個緩存還必須是分散式的。於是就換成了redis,這樣系統都可以連接到。但是數據量太大,需要分頁查詢,這就有點頭痛了。還好redis是可以支持有序集合的,而且可以通過zrange來獲取指定範圍數據。
3、增加了需求
這些數據要在運維界面里還要可以按條件過濾,這個就非常頭疼啦,redis沒有條件過濾啊。即使過濾出來了數據要顯示在界面上必須分頁。
問題思考
最終突然發現如果存在資料庫里是不是很好解決?但是存在資料庫里就會有大量寫操作的問題,而且數據這麼大,像Mysql單表很容易就破了。所以我想著是不是還是在nosql的基礎上解決。
這裡就有幾個問題:大數據量的排序、查找過濾、分頁。
先不管這麼多,如果使用Mysql的話,除了大表保存問題,查找、過濾、分頁功能都是直接使用sql實現的,開發起來簡單。
mysql
如果使用mysql存儲後,如果要查一些數據怎麼整?先看下麵的這段代碼:
SELECT t.*
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,100
這裡最直接的就體現了兩點:先排序,然後取分頁的數據。好了,這裡有幾個問題:
1、使用了*返回欄位,全欄位返回的問題就是要掃描全表
2、進行了ORDERBY排序,我測試的這個表只有幾百萬數據
3、最後分頁是取的130萬開始的100條,等於是要掃描130萬後才開始
我隨便跑了一下執行了:5.5秒左右。有沒有辦法讓它快一點呢?確實有,網上找找挺多的。
首先,看看只返回部分欄位是不是快一些?
SELECT t.creationDate
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,100
上面的SQL語句,改造後,只返回一個欄位,再執行。2.9秒了。
那麼取1條數據的速度會不會快一些呢?
SELECT t.creationDate
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,1
執行上面的sql後發現時間還是2.9秒,這說明取1條的數據也是這麼慢,那慢的肯定就是排序啦。
然後使用這一條取出來的數據作為條件,直接在集合中定位到分頁數據
SELECT ofOffline1.* FROM ofOffline1 WHERE ofOffline1.creationDate <(
SELECT t.creationDate
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,1
)
ORDER BY ofOffline1.creationDate desc
LIMIT 100
這是網上查到的SQL,思路就是先使用子查詢定位到第130萬條記錄,然後從它開始取後面的99條。時間差不多3.9秒左右。這說明這樣的優化還是有效的。
使用一下索引
我想了想如果加個索引是不是可以提升性能呢?SQL中只使用了creationDate排序和過濾,那麼就用它建個索引試試吧。
還是測試一下最簡單的那條SQL
SELECT t.*
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,100
結果是:5.5秒左右,沒變化
那麼看看前面有子查詢的情況:
SELECT ofOffline1.* FROM ofOffline1 WHERE ofOffline1.creationDate <(
SELECT t.creationDate
from ofOffline1 t
ORDER BY t.creationDate desc
LIMIT 1300000,1
)
ORDER BY ofOffline1.creationDate desc
LIMIT 100
不錯,執行結果:0.599秒。
好吧,本文先到這,後面再學習一下mangodb,按理它會比較適合我們的場景。