數據庫大字段(Clob, Blob)不適合存儲超過1MB的數據
通常數據庫都提供Clob,Blob,Text,Long等大字段類型來存放超過4K的數據,然而這絕不意味着應該使用大字段來保存超過1MB以上的數據文件。之所以有大字段,往往是因為varchar類型有一定的長度限制,例如4K。超過此長度的文本和二進制數據必須使用大字段保存。不過通常情況下,大字段不意味着保存很大的文件,通常只是幾十到幾百KB的數據,例如很長的文章,圖標,小圖片等等。超過1MB以上的數據保存在數據庫有諸多的性能問題:
速度慢
Web Server可以直接讀取硬盤文件,然后返回文件給客戶端,或者應用服務器讀硬盤文件返回客戶端,其效率要遠遠超過應用服務器訪問數據庫讀取數據返回客戶端。
操作不方便
必須把數據庫打開一個流,構造一個Buffer,然后再輸出一個ServletOutputStream。占用數據庫連接,加重數據庫訪問負載不說,如果用戶突然中斷下載,還需要處理數據庫關閉動作,容易造成性能問題。如果把整個數據讀入內存再輸出,則內存占用非常客觀。如果是硬盤文件,只要返回一個URL就可以了。即使你不希望用戶直接訪問到文件,你也可以構造一個IOStream來輸出文件,既不會占用數據庫資源,傳輸速度也快。
性能有問題
特別的情況是,如果並發很多用戶來下載大文件的時候,應用服務器要占用非常多的內存來緩存文件內容,假設並發10個用戶,下載10MB的文件,JVM的峰值就至少需要100MB內存來支撐,很容易造成JVM崩潰。
Oracle其實還有一種File的Blob類型,雖然也是Blob,但是實際上File是保存在硬盤上的,這種方式的你可以試試看,只不過我覺得這種方式還不如直接操作文件方便,既然原理是一樣的。
另外補充一點,常規的數據庫備份都是無法備份Blob數據的,所以如果你把文件都保存到Blob里面去的話,數據庫的備份是一個很頭疼的大問題,你必須單獨寫程序把blob數據讀出來,再寫到硬盤文件去,再備份文件。而你如何把文件放在硬盤某個目錄下面,而不是做為blob放在數據庫里面,那備份簡直易如反掌。
當然保存文件的方式的缺點就是文件不能重名,否則會覆蓋,這個問題也不難解決,一般的fileupload API碰到重名都會有很多改名保存的策略;另外一點就是操作系統一個目錄下面可以放的文件數量有限制,這個限制通常和文件系統的inode數量有關系,例如一個目錄下面只能放1024個文件之類,然而這個問題同樣可以通過file upload的一些保存策略解決掉,例如再增加一個子目錄存放什么的。Oracle其實還有一種File的Blob類型,雖然也是Blob,但是實際上File是保存在硬盤上的,這種方式的你可以試試看,只不過我覺得這種方式還不如直接操作文件方便,既然原理是一樣的。