【連載】關係型數據庫是如何工作的?(2) - 時間複雜度

基礎知識

很早之前,開發者必須準確的計算他們編寫代碼的操作指令數量,他們深刻理解使用的數據結構和算法,因爲那個時候CPU計算能力和內存儲存空間都很小,需要最大限度的利用起來,經不起浪費。

在這一部分我會介紹一些這方面的內容,因爲對於理解數據庫它們確實很重要。另外,還會介紹數據庫索引的概念。

時間複雜度O(1) vs O(n2)

時至今日,很多開發者都不關心時間複雜度,大部分時候也許他們是對的。但是當你需要處理海量數據或者對程序執行時間非常敏感時(毫秒級別),理解時間複雜度就變得非常重要了,而不幸的是,數據庫正好同時面臨以上兩個問題。時間複雜度能夠幫助我們理解後續要介紹的基於成本的優化機制。

理論

時間複雜度是用於表明一個算法處理指定大小的數據集合會花費多長時間。爲了便於描述時間複雜度,計算機學科採用大O表示法。這種表示法用一個函數描述一個算法處理指定大小的數據集合需要多少個操作。

例如,如果一個算法的時間複雜度是 “O( some_function() )”,並且數據集合大小是“a_certain_amount_of_data”,那麼這個鬚髮處理該數據集合需要“some_function(a_certain_amount_of_data)”個操作。

實際上,時間複雜度描述的重點並不是數據集合的大小,而是隨着數據集合大小的增加,相應的算法處理操作數量的變化趨勢,簡而言之,時間複雜度描述的是數據集合大小和操作數量之間的關係,並不能表示精確的操作數量。

這裏寫圖片描述
上圖可以看到不同時間複雜度的對比,從途中可以看到,當數據集合大小從1上升到10億時:

  1. O(1) 操作數始終保持不變,因此其也稱爲常量複雜度;
  2. O(log(n)) 操作數增加很少;
  3. O(n2) 是最糟糕的複雜度,因爲其操作數激增;
  4. O(n)和O(log(n)*n)操作數也有一個明顯的增加;

例子

實際上,在數據量較小時,O(1) and O(n2)的差異可以忽慮不計。假設數據集合大小是2 000,那麼:

  1. O(1)會花費1個操作;
  2. O(log(n))會花費7個操作;
  3. O(n)會花費2000個操作;
  4. O(n*log(n))會花費14 000個操作;
  5. O(n2)會話費4 000 000個操作;

表面看來,O(1) 和 O(n2)貌似差距很大,但實際運行時,它們只有大概2ms(大概就是眨下眼睛的時間)左右的時差。這是因爲現代處理器每秒可以處理數以億計的操作,這也是對於大部分IT項目,性能和優化並不是個問題的原因。

但是當處理海量數據時,理解時間複雜度仍然很重要。假設數據集合大小是1 000 000時,那麼:

  1. O(1)會花費1個操作;
  2. O(log(n))會花費14個操作;
  3. O(n)會花費1 000 000個操作;
  4. O(n*log(n))會花費14 000 000個操作;
  5. O(n2)會話費1 000 000 000 000個操作;

這樣看來,O(n2) 實際耗費的時間估計夠你喝杯咖啡了,如果再加一個0,也許你就可以小睡一會了。

進階理解

一些經驗數據:

  1. HASH表的搜索時間複雜度是O(1) ;
  2. 平衡樹的搜索時間複雜度是O(log(n));
  3. 數組的搜索時間複雜度是O(n);
  4. 最好的排序算法的時間複雜度是O(n*log(n)) ;
  5. 最糟糕的排序算法的時間複雜度是O(n2) ;

在後續章節,會介紹這些算法和數據結構。

有許多種類型的時間複雜度:

  1. 平均場景下的時間複雜度;
  2. 最壞場景下的時間複雜度;
  3. 最好場景下的時間複雜度;

我們談論的一般是指最壞場景下的時間複雜度。雖然我們只談論時間複雜度,但複雜度也可以用於表示:

  1. 算法的內存消耗;
  2. 算法的磁盤IO消耗;

當然了,也有比O(n2)更糟糕的時間複雜度,例如:

  1. n的4次方:我提及的一些算法就是這個時間複雜度;
  2. 3的n次方:在後續文章我們可以看到這種時間複雜度的算法;
  3. 階乘n:你永遠不會得到結果,即使當數據量較小時;
  4. n的n次方:如果是這個複雜度,那你應該問問自己,你還是做IT的嗎?快點換個行業吧,哈哈!

說明:我們並沒有給出大O表示發的詳細說明,僅僅闡述了其思想。如果想詳細瞭解,則可以查看維基百科:大O表示法

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