------------更新:201501071730------------
評論中又有一位【笑東風】兄給出改善建議,在此先感謝他。原理是借助行數較多的一個系統視圖sys.all_columns與自身做cross join,以得到大量現成行數,詳情請見回復。在我的原文中我也提到考慮過這種借助現有系統對象得到行的方法,但我想當然認為這樣會導致訪問基礎表,性能不會好,所以試都沒試就pass了,但事實證明我錯了,他的法子經測性能比倍增法好太多,再次自我教訓,實踐才是硬道理?。?!再次感謝【笑東風】兄。最終實現如下:
/*----------------------函數:生成行 0.01Author:AhDungUpdate:201412310925----------------------*/CREATE FUNCTION dbo.FMakeRows(@num INT)RETURNS TABLERETURN (SELECT TOP (CASE WHEN @num IS NULL OR @num<0 THEN 0 ELSE @num END) ROW_NUMBER() OVER(ORDER BY a.object_id) AS 'RowNo'FROM sys.all_columns a CROSS JOIN sys.all_columns b)
------------更新:201501061241------------
評論中有朋友提到不如用with,我理解他說的是CTE遞歸,在此先感謝一下這位【空紫竹】兄提出建議。遂試了下用CTE實現,代碼如下:
CREATE FUNCTION dbo.FMakeRows2(@num INT)RETURNS TABLERETURN (WITH cte AS (SELECT 1 AS 'RowNo',1 AS 'Lv'UNION ALLSELECT RowNo+Lv,Lv*2 FROM cte WHERE RowNo+Lv<=@numUNION ALLSELECT RowNo+Lv*2,Lv*2 FROM cte WHERE RowNo+Lv*2<=@num)SELECT RowNo FROM cte)
功能一樣,原理是遞歸倍增,語句變少了,但性能比不上原文的方法,16384行上述方法要400ms左右,與逐行法差不多,而原文方法只要140ms,所以算不上好方法,權當學習一下CTE遞歸知識。如果我的實現有問題,還望路過大俠指點,謝謝。
------------原文:201412311300------------
作用:傳入整數x,返回一張x行的表,只有一列RowNo,存儲各行序號。
對于這個需求,我先是找有沒有現成的函數或過程,結果是沒找到,如果路過的朋友知道,還望告知,謝謝。
使用示例:
至于該函數具體可以應用到哪些場景,只可意會,需要的人自然覺得有用,覺得沒用的說明不需要。上代碼:
/*----------------------函數:生成行 0.01Author:AhDungUpdate:201412310925----------------------*/ALTER FUNCTION dbo.FMakeRows(@num INT)RETURNS @t TABLE (RowNo INT)BEGINIF @num IS NULL OR @num <= 0 RETURNINSERT @t VALUES(1)DECLARE @no INT = 1WHILE @no*2 <= @numBEGININSERT @t SELECT RowNo+@no FROM @tSET @no *= 2ENDINSERT @t SELECT TOP (@num-@no) RowNo+@no FROM @tRETURNEND
實現說明:原理是先給@t塞一個初始行,完了循環insert自身,如此1變2、2變4、4變萬物……,每一圈后@t的行數都是上一圈的2倍,直到行數x2大于所需行數(@num)前打住,即要把行數控制在小于等于@num的范圍內,最后從現有行中抽取一部分補齊所差的行。例如,需要的行數是13,轉到3圈后,@t有8行,就要打住了,因為再轉就成16行了,8距離13所差的5行最后通過從@t中抽取top 5補齊。
實現該函數一開始想到的是根據@num循環,每圈插一行,需要幾行就轉幾圈(逐行法),邏輯很簡單,但這樣做很老實,事實證明效率也不如上述方法(行數倍增),兩種方法經測試到500行時就有明顯差異了,到16384行時,倍增法在140ms左右,逐行法400ms左右,我想原因就是倍增法大大減少了循環圈數,16384行只需轉14圈,而逐行法要老老實實轉足16384圈吶~怕怕。
也想過從某個必定存在的系統表/視圖獲取行,如sys.objects,但這樣會訪問基礎表,即使你根本不select它的任何字段,這樣性能必然不如純內存操作來的好,試都不用試。再說也不地道,作為函數,依賴越少越健壯。
路過朋友如有更好方法,還請不吝賜教,非常感謝。
新聞熱點
疑難解答