1. 為什么Redis不共享包含字符串的對象?
當服務器考慮將一個共享對象設置為鍵的值對象時,程序首先需要檢查給定的共享對象和鍵想要創建的目標對象是否完全相同,只有在共享對象和目標對象完全相同的情況下,程序才會將共享對象用作鍵的值對象,而一個共享對象保存的值越復雜,驗證共享對象和目標對象是否相同所需的復雜度就越高,消耗的CPU時間也越多:
- 如果共享對象是保存整數值的字符串對象,那么驗證操作的復雜度為O(1);
- 如果共享對象是保存字符串值的字符串對象,那么驗證操作的復雜度為O(N);
- 如果共享對象是保存了多個值(或者對象)的對象,如果列表對象或者哈希對象,那么驗證操作的復雜度將會是O(N^2);
因此,盡管共享更復雜的對象是可以節約更多的內存,但受到CPU時間的限制,Redis只對白喊整數值的字符串對象進行共享。
2. 為什么有序集合需要同時使用跳躍表和字典來實現?
在理論上,有續集和可以單獨使用字典或者跳躍表的其中一種數據結構來實現,但是無論單獨使用字典還是跳躍表,在性能上對比起同時使用字典和跳躍表都會有所降低。
舉個例子:如果我們只是使用字典來實現有序集合,那么雖然以O(1)復雜度查找成員的分值這一特性會被保留,但是因為字典以無序的方式來保存集合元素,所以每次在執行范圍型操作——比如ZRANK、ZRANGE等命令時,程序都需要對字典保存的所有元素進行排序,完成這種排序至少需要O(NlogN)時間復雜度,以及額外的O(N)空間復雜度(因為要創建一個數組來保存排序后的元素)。
另一方面,如果我們只使用跳躍表來實現有序集合,那么跳躍表執行范圍型操作的所有優點都會被保留,但是因為沒有了字典,所以根據成員查找分值這一操作的復雜度將從O(1)上升到O(logN)。
以為以上原因,為了讓有序集合的查找的范圍型操作都盡可能快地執行,Redis選擇了同時使用字典和跳躍表兩種數據結構來實現有序集合。