大數據量請求查詢數據庫優化思考

業務場景:

任務體系越來越受到活動的青睞,例如最近的淘寶和京東雙十一活動,都是採用任務類型的活動,我司近幾個月的活動也多采用類似的任務體系,分享、關注、點贊、投幣、投稿等,既然是活動,就限制了活動的範圍是活動稿件或指定稿件上的點贊/投幣行爲,因此Job監聽用戶點贊、投幣時,需要查詢點贊或者投幣的是否是活動稿件。

在數據庫中,稿件業務方有單獨的表,但是如果是活動稿件,也會進入活動單獨的活動稿件表,因此,每當有一條點贊/投幣的消息到來時,需要判斷該條信息的稿件id是否屬於活動稿件,就需要查詢活動稿件表。當數據量不多時,直接查db是沒有問題的,但是數據量大的時候,很容易把數據庫打爆,然後限流。。。

原始查詢:

"SELECT `id` From likes WHERE sid = ? and wid = ? and `state` != -1"

優化一:既然直接查數據庫不可以,可以改走內存哇。先把該活動下的稿件拉出來,每幾分鐘拉一次,放在一個協程裏,然後設置一個內存變量map,稿件id爲map的鍵,值爲空結構體就好struct{}{}。每次來消息時候,就判斷是否存在即可:

if _, ok := s.XXmap[m.ID]; ok {
	xxx
}

sql查詢如下:

SELECT wid FROM xxx WHERE state=1 AND sid=? ORDER BY type

思考:

走內存是沒問題的,但是這麼查,如果稿件量特別大,還是容易出問題,因此,考慮分段查詢,使用limit

優化二:

sql查詢如下:

SELECT wid FROM xxx WHERE state= 1 AND sid = ? ORDER BY id LIMIT ?,?

這樣可以先查詢一個總量,然後使用for循環,分批次100個100個的查,上面的sql填充limit offset,limit

for i := 0; i < count; i += 100 {
    //查詢
}

思考:

limit ?,?會有深度分頁問題,因儘量少這麼使用,因此考慮更好的分批次查詢方式。

優化三:

SELECT id,wid FROM xxx WHERE sid=? and `state`!=-1 and id > ? ORDER BY id ASC LIMIT ?

如上,同樣是使用limit,但是在前面,加了一個id > ?的判斷,不加這個判斷依舊是查所有的數據,加了之後,第一次傳0,第二次傳第一次查出來的最後一個id,這樣就能比較好的分批次查詢了。整個協程代碼如下:

func (s *Service) loadXXXArc(sid int64) (data map[int64]struct{}, err error) {
	var (
		i   int64
		tmp = make(map[int64]struct{})
		res []*l.XXX
	)
	for {
		time.Sleep(100 * time.Millisecond)
		res, err = s.loadList(context.Background(), sid, i, _objectPieceSize, _retryTimes) //封裝的查詢方法,i對應sql中的id>?,_objectPieceSize常量對應limit?
		if err != nil {
			log.Error("loadXXXArc Err %v", err)
			break
		}
		if len(res) == 0 {
			log.Warn("loadXXXArc load data finish")
			break
		}
		for key, val := range res {
			tmp[val.Wid] = struct{}{}
			if key == len(res)-1 {
				i = val.ID   //取上一次查詢的最後一個id賦值
			}
		}
	}
	data = tmp
	return
}

func (s *Service) loadArc() {
	data, err := s.loadXXXArc(s.c.Eleven.ElevenSid)
	if err != nil {
		return
	}
	s.Arc = data
}

func (s *Service) loadArcproc() {
	for {
		time.Sleep(5 * time.Minute)
		s.loadArc()
	}
}

//最後,在service層的New()中調用即可
s.loadArc()
go s.loadArcproc()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章