最近在做oracle到mysql的資料庫的移植過程。兩者之間的諸多差別(比如mysql不支援ado、函式不一致、唯一索引限制不一樣等等)都易於解決,但有乙個問題卻困擾我們良久:oracle的遞迴查詢(select... from ... start with ... connect by ... where...子句)在mysql中不受支援。
在sql server2000(2005已經支援遞迴查詢)和db2中,都可以使用儲存過程的方式,在儲存過程中完成對資料庫的遞迴檢索,並返回記錄集的方式實現;但是mysql資料庫可以用儲存過程完成遞迴,但儲存過程本身不能返回臨時的記錄集。
首先,最先想到的是採用臨時表的方案解決(網上很多大哥都用的這種方案),但做了乙個效率測試,在10w條資料中使用臨時表遞迴檢索,1分鐘過去了,5分鐘過去了,10分鐘過去了,半小時過去了……沒有返回(後邊測試了500條資料需要接近8秒鐘時間)。臨時表方案效率肯定是有問題的。
然後,公司的db大佬支招了:使用乙個字串字段(稱為「編碼」,欄位名稱比如命名為innerid)來表示記錄的父子關係。核心思想是為需要遞迴的表新增三個字段(摘錄自同事的設計文件):
各個記錄行的「編碼」如下圖所示。
這種方案的確可以很好的解決查詢某行下所有子行的符合條件的記錄集的問題。只需要形如select * from *** whereinnerid like "a0zz%" [and othercondition]的查詢條件即可檢索出a0zz記錄及其所有下屬節點的符合條件的記錄集。
但是,導致了另外乙個問題的產生:當對某個父記錄集節點(特別是位於根節點下的二級節點)進行移動位置時,將會是致命的(需要修改所有的innerid,並且如果要考慮資料夾的合併的話,那將更加複雜),如果還要考慮多終端的併發性問題,會出現的問題將非常複雜。
所以,這個方案可以作為備選方案(需要在我們的產品spec中加入一些limitation),但最好能找到更好的解決方案。
最好,在我們同事的不懈努力下,在mysql的論壇中找到了一種更加合理的方案。
其實,這個方案我們也應該早就可以想到,特別是在倡導「扁平化管理」的今天。它的核心思想就是將遞迴所實現的層級化結構,使用數字按照巢狀的思路實現扁平化,截圖(來自原網頁):
(層級化結構)
**化為巢狀後的平坦化結構)
具體方案可以參考原始網頁:
使用這種方案,相比於前乙個方案,一方面在查詢的時候可以省掉字串的like關鍵字,有助於提公升效率;另外一方面,在對資料集進行修改時,也只需要對增加的左值和右值節點,進行批量的update(增加一定的數字或者減少一定的數字,但效率需要測試),不需要更複雜的邏輯,在併發性上也可以處理得更好。
總結:其實扁平化不光是在管理上,也可以在技術中,mysql的遞迴查詢只是乙個簡單的例子,我們在開發過程中,如果能夠換個角度想問題,也許可以有更多更好的解決方案。
mysql 遞迴 mysql遞迴查詢
find in set 函式 函式語法 find in set str,strlist str 代表要查詢的字串 strlist 是乙個以逗號分隔的字串,如 a,b,c 此函式用於查詢 str 字串在字串 strlist 中的位置,返回結果為 1 n 若沒有找到,則返回0。concat 它用於連線n...
mysql遞迴查詢統計 mysql遞迴查詢
樣例資料 create table treenodes id int primary key,nodename varchar 20 pid int select from treenodes id nodename pid 1 a 0 2 b 1 3 c 1 4 d 2 5 e 2 6 f 3 7...
mysql 遞迴查詢效率 mysql 遞迴查詢
set stemp set stempchd cast id as char 轉化資料格式 while stempchd is not null do 開始迴圈 set stemp concat stemp,stempchd 字串拼接 select group concat id into stem...