自定義排序之數據庫設計
之前做過的項目有項需求,就是要對一個普通的列表進行自定義排序功能,當初構思了幾個方案,各有所長,按需使用,下面就一一來介紹這幾個方案。
注:這里的自定義排序就是操作列表的某項進行位置交換。
1. 單表單列結構(數組結構)
此設計是使用一個表中的一列來表示數據的序號,通常我們使用的方法就是這種。
數據表tb_data(n):
| data | index |
|---|---|
| ··· | 0 |
| ··· | 1 |
| ··· | 2 |
這里規定序號從0開始遞增。
其基本數據操作如下:
- 增 → 當增加一個數據時,定義data的序號為數據總數量值。
- 刪 → 當刪除一個數據時,將大於該序號的數據的序號都減1。
- 改 → 當修改位置將數據a從x移動到y時,若x小於y,則將(x,y]范圍內的數據序號都減1;若x大於y,則將[y,x)范圍內的數據序號都加1(注:修改數據庫時,要先將a的序號x修改為未被使用的序號z,然后再修改范圍內的數據,最后再將z修改為y,順序不能亂)。
- 查 → 當查找數據時添加 order by index 即可得到自定義排列的數據,查找第n個數據時查找條件為 index=n-1 即可。
總結:此方法查找速度最快,修改速度最慢。
2.單表雙列結構(鏈表結構)
此設計是使用一個表中的兩列來表示數據的序號,一列表示該數據的前置id,一列表示該數據的后置序id(id為數據表本身的自增序號),即相當於我們經常使用的雙向鏈表。
數據表tb_data(n):
| id | data | pre_no | next_no |
|---|---|---|---|
| 0 | ··· | -1 | 1 |
| 1 | ··· | 0 | 2 |
| 2 | ··· | 1 | 3 |
| 3 | ··· | 2 | -1 |
這里規定第一個數據的pre_no為-1,最后一個數據的next_no為-1。
其基本數據操作如下:
- 增 → 當增加一個數據a時,先查找出最后一個數據b的id號,a的pre_no定義為b的id號(若此數據為第一個則定義為-1),next_no定義為-1,再將b的next_no定義為a的id號。
- 刪 → 當刪除一個數據a時,取出a的pre_no和next_no,將pre_no對應的id的數據的next_no修改為a的next_no,將next_no對應的id的數據的pre_no修改為a的pre_no。
- 改 → 令位置x-1、x+1數據分別為b、c,位置y-1、y、y+1的數據分別為d、e、f,現修改位置將數據a從x移動到y時,
當x小於y時,修改b的next_no為c的id,修改c的pre_no為b的id,修改e的next_no為a的id,修改f的pre_no為a的id,最后修改a的pre_no為e的id,next_no為f的id;
當x大於y時,修改b的next_no為c的id,修改c的pre_no為b的id,修改d的next_no為a的id,修改e的pre_no為a的id,最后修改a的pre_no為d的id,next_no為e的id。 - 查 → 當查找第n個數據時,需要先查找出第一個數據,在根據第一個數據逐個往后查找數據的next_no,查找n次后得到第n個數據。
總結:此方法查找速度最慢,修改速度最快。
3.雙表雙列結構(分頁結構)
此設計是使用一個頁碼表記錄全部頁碼和頁碼的序號范圍,另一個數據表來記錄基本數據、自身序號和頁碼,通過在一個表中給數據設置不同的序號和頁碼來達到分頁排序的效果。
頁碼表tb_page:
| tb_name | page | start_index | end_index |
|---|---|---|---|
| tb_data0 | 0 | 1 | 1000 |
| tb_data0 | 1 | 1 | 1000 |
| tb_data0 | 2 | 1 | 120 |
| tb_data1 | 0 | 1 | 1000 |
| tb_data1 | 1 | 1 | 130 |
table_name為一個基本數據表的表名,對於每一個table_name,其對應的page都從0開始遞增且不能重復,每個page有一定的數據范圍(這里設定為一頁有1000條數據),則每個數據表對應的數據總量即可計算出來。
基本數據表tb_data(n):
| data | page | index |
|---|---|---|
| ··· | 0 | 1 |
| ··· | 0 | ··· |
| ··· | 0 | 1000 |
| ··· | 1 | 1 |
| ··· | 1 | ··· |
| ··· | 1 | 1000 |
| ··· | 2 | 1 |
| ··· | 2 | ··· |
| ··· | 2 | 120 |
data為數據域,記錄基本數據,對於每一個不相同的data都有對應的page和index,通過page、index和每一頁的數據范圍即可計算出對應的全局序號。
其基本數據操作如下:
- 增 → 當增加一個數據時,先從頁碼表中查找出最后的page及其對應的start_index和end_index,若end_index-start_index+1沒有數據超出范圍,則插入數據的page不變,index為end_index+1,若超出范圍,則需在頁碼表中新建一頁,插入數據的page自加一,index賦值初始值。
- 刪 → 當刪除一個數據時,因為需要保證除末頁以外的頁碼的數據范圍都為規定值,所以需要對刪除數據對應的頁碼及以上頁碼的數據進行調整,對於刪除數據的頁碼,可以通過對比該數據在頁碼中的相對位置來調整較小數據量的一方數據執行加減1,對於大於其的頁碼,可以將每一頁的首數據調整為上一頁的末數據(末頁數量為0即可將末頁刪除)。
- 改 → 當修改位置將數據a從x移動到y,計算x、y對應的頁碼,當x、y的頁碼相同時,只需調整該頁數據,可通過對比x到y的數量和頁碼數量來決定調整x、y范圍內還是范圍外的數據信息;當x、y頁碼不同時,可通過對x、y在頁碼中的相對位置來調整較小數據量的一方數據執行加減1,若x小於y,(x,y]范圍內的頁的首數據調整為上一頁的末數據,若x大於y,[y,x)范圍內的頁的末數據調整為下一頁的首數據。
- 查 → 當查找數據總量時,可以通過查找頁碼表計算得出;當查找序號為n的數據時,可以通過頁碼表計算得到對應的page和index,然后再通過查找數據表取得數據(由於頁碼表的數據會經常使用,所以最好從數據庫取出一次后保存在內存中再進行使用即可提高速度)。
總結:此方法查找速度和修改速度比較均衡,適合大多數情況使用。
