天天看點

海量存儲系列之二

在上一篇裡面,我們對資料庫的抽象的組成原理進行了簡單的描述。在這一篇裡面,我們一起來看看,如何能夠使用kv這樣的工具。來完成關系代數運算。

那麼,讓我們先來熱熱身:

海量存儲系列之二

這是一組資料,以pk作為主鍵,user_id和name是外key.

那麼,如果我要運作查詢:select from tab where id = ?

應該如何進行呢?

這裡需要一些額外的知識,在資料結構中,有那麼一種結構,可以用于處理按照某個key找到value的過程,抽象來看,一種方法是二分查找法,一種方法是hash.

如果各位是java使用者,那麼二分查找的實作可以認為是個treemap的實作,而hash的方法則可以認為是hashmap的實作。如果是個c/cpp的使用者,那麼就二分查找就對應map實作。而hash實作則對應stl裡面的hash_map。

那麼,這裡的這個問題,我們就很容易可以解決了

以id作為map的key,以其他資料作為value,把所有資料都放入到map裡面,然後再使用id=1作為key,從map中找到對應的value傳回即可。(這一個部分,我們在後面的章節裡面還會介紹,現在大家隻需要有個大概的印象即可)

怎麼樣?是不是很簡單?那麼,我們來讨論更進一步的問題:

如果我想找到符合select from tab where user_id = 0的所有結果,應該如何去作?

仔細想想。那麼第一種做法一定是這樣。

把整個集合内的所有資料,都拿出來,然後找到user_id的數字,如果user_id=0,那麼就認為是符合要求的記錄,直接傳回。

如果不是user_id=0,那麼不比對,丢棄這條記錄即可。

這樣一定可以找到所有符合要求的記錄。

然而,這樣作,帶來的問題是,我有多少條記錄,就需要進行多少次這樣的比對,那麼,假設有100000000000000000條記錄,就需要比對這樣多次,才能找到符合要求的記錄。這是個悲劇。。

那麼,怎麼解決這個悲劇呢?

于是有些聰明人就又想起了map結構,hash或tree,不都可以按照k找到value麼。那我們這裡也可以利用這個map結構嘛。。

海量存儲系列之二

也就是說,以user_id作為key,id作為value,建構一個map.不就又能進行快速查詢了麼。

于是,就有了資料庫最重要的一個結構“索引” 這種以外鍵作為key,主鍵作為value的東西,有個專有的名字,叫做二級索引。

有了二級索引,我們的所有查詢,都可以以接近o(logn)(有序資料),或o(1)的效率找到我們需要的資料。是不是很爽?

但這不是銀彈,你付出了空間成本,本質來說就是空間換時間的過程。同時,也會降低寫入的效率。

怎麼樣?了解了沒?如果自認為對這些都了解了,那麼我們再來看一個問題:

海量存儲系列之二

如果我要找的是:select …where user_id = ? and name = ‘襪子’

應該怎麼做呢?

估計很多人都立刻又會想起那個map,對的,但在這裡,我想給出以下的幾種查詢的模式:

1. 周遊所有資料,取出一條以後,檢視user_id = 0 and name=’襪子’是否符合要求,如果符合,則傳回資料。

這是個合理的政策,空間最為節省,但帶來的損耗是要周遊所有的資料。

2. 如果有個user_id -> pk的索引

海量存儲系列之二

,那麼我們可以先按照user_id,找到一組符合要求的pk list.然後再根據pk list,再回到

海量存儲系列之二

取出符合要求的資料後,判斷name=‘襪子’這個條件,如果符合,就傳回,不符合,就丢棄。

這是個折衷政策,在空間和性能中,盡可能的找到個合理的區間的政策。

題外話,這個“根據pk list,再回到pk=>整個資料的kv表中,找出符合要求的資料後,判斷name=‘襪子’這個條件,如果符合,就傳回,不符合,就丢棄”的政策,在資料庫有個專有名詞,叫回表。

3. 組合索引

這是個新名詞兒,但其實也是個很簡單的概念。

直接上圖:

海量存儲系列之二

:-),其實就是個很簡單的政策,先比較user_id進行排序,如果user_id相同,那麼比較name排序。

這樣,假定我們有100000條記錄,屬于100個使用者,那麼平均來看,每個使用者就隻有1000條記錄了。

原來要回表1000條記錄才能找到符合要求的資料,而如果使用組合索引,這1000條,也可以使用o(log2n)或者o(1)的政策進行檢索啦。

在很多場景中,都能夠提升效率和速度。但付出的是更多的存儲空間。

好啦,這篇就介紹到這裡,留個題目給大家:

海量存儲系列之二

假設有這麼一組資料,性别有4種,user_id是一對多的關系,如果我想查詢

select * from tab where user_id in (?,?,?,?) and 性别=’不明’

如何進行索引建構能夠獲得比較好的效果呢?

本文來源于"阿裡中間件團隊播客",原文發表時間" 2011-12-07"