在講我們自己的數據結構之前,我們還是先來分析一下DotNetNuke的UserDefinedTable這個模塊的數據結構,我個人從這個模塊中受益匪淺。
我們之前曾經說過,UserDefinedTable用三張表,就完成了支持無限字段的動態窗體的數據結構,這似乎已經是絕對不可能再精簡的數據結構了(當然,還需要借助系統的Users表,來區分用戶),這三張表是UserDefinedFields、 UserDefinedRows和UserDefinedData這三張表,所有的用戶數據,都存儲在UserDefinedData這張表中,我們將這個數據結構截一張圖放在下面,讓大家可以看清楚。
為了存儲所有格式的字段(如日期型、大文本型等等),因此,FieldValue采用了ntext字段。其實,這樣的存儲在DotNetNuke中已經有了,就是我們的模塊設置表TabModuleSettings,為了存儲各種類型的數據,比如布爾型、整數型、日期型等等,但是TabModuleSettings采用的是nvarchar(2000)。
這樣的數據結構就是為了可以為一條記錄提供無限的字段數量,而不需要我們去動數據結構;這樣的數據庫設計方式其實在國內各種應用裡面也是屢見不鮮的。我們舉一個例子,來講一下數據是如何存儲的,比如,我們有一個定義的窗體,是用來做人員登記的,存儲姓名、性別和年齡(靠,非常弱智的例子),我們最終的結果是這樣的:
張三 男 25
(為了簡單起見,性別我們也直接用字符串了,不過為了避免磚頭橫飛,還是解釋一下。)而在數據庫中,是這麼存儲的,見下圖:
上面這些,其實寫過程序的朋友們基本上都比較清楚了,這裡只是做一個簡單的介紹而已。這樣的存儲,比較痛苦的就是如何把數據“拿出來”了,比如我們寫一條SQL語句,把RowID為2的那三個字段拿出來,形成一張橫表的話,需要用到LEFT JOIN方法,我們將SQL語句寫在下面:
SELECT R.UserDefinedRowID, D1.FieldValue As 姓名, D2.FieldValue As 性別, D3.FieldValue As 年齡
FROM UserDefinedRows R
LEFT JOIN UserDefinedData D1 ON R.UserDefinedRowID=D1.UserDefinedRowID AND D1.UserDefinedFieldID=10
LEFT JOIN UserDefinedData D2 ON R.UserDefinedRowID=D2.UserDefinedRowID AND D2.UserDefinedFieldID=11
LEFT JOIN UserDefinedData D3 ON R.UserDefinedRowID=D3.UserDefinedRowID AND D3.UserDefinedFieldID=12
WHERE R.UserDefinedRowID=2
而最後得到的結果,就是我們希望的一張橫表,如下圖所示:
在論壇中,UDT的TeamLeader Sebastian Leupold曾經這樣描述過他的UDT數據結構,大家有興趣的話可以去看一下。
OK,現在想象一下,如果我們有30個自定義字段,這個SQL語句會有多長呢?而一個自定義的Form 中,有30個字段,應該不是什麼過分的要求吧?更重要的是,LEFT JOIN這種方式,還是效率比較低下的。而更過分的是,我們的UserDefinedTable模塊,采用了應該是更為低下的方式來處理數據,就是將數據一條條取出來,然後在內存中動態生成一張DataTable,然後再將這個DataTable綁定到顯示控件上。按照我個人的理解,我覺得這種方式毫無疑問是比LEFT JOIN更為效率低下的一種處理方式,所以,在另外一個帖子裡(抱歉,翻了半天,仍然找不到那個帖子,順便鄙視一下DotNetNuke Forum的搜索功能,基本上沒有能用的時候),Sebastian Leupold也親口承認說,UDT對於超大量的數據是不適合的。所以,其實UDT的問題,是“結構性問題”,如果我們需要超越UDT,開發我們的 Form,並且可以容納比如百萬級數據的話,一定要重新設計一下UDT的結構,將其中有用的為我所用;其中不好的予以改進。
下一節我們討論如何對這個數據結構進行優化,從而達到我們的要求。