在 SQL Server 中儲存圖片主要有兩種策略,各有優劣:
| 策略 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 資料庫內部儲存 (VARBINARY(MAX)/IMAGE) | 交易一致性、備份還原單一化、權限控管集中 | 資料庫膨脹、備份時間增加、串流效能較差 | 小型圖片、機密文件、需 ACID 保證 |
| 檔案系統儲存 + 資料庫存路徑 | 資料庫精簡、串流效能佳、利用 CDN/靜態檔案伺服器 | 交易一致性需自行處理、備份分離、權限分散 | 大量/大型圖片、公開內容、高併發讀取 |
| FileTable / FileStream (SQL 2012+) | 兼具兩者優點、支援 Win32 API 存取 | 需啟用 Filestream、版本限制 | 現代應用、文件管理系統 |
CREATE TABLE dbo.Images (
ImageID INT IDENTITY(1,1) PRIMARY KEY,
FileName NVARCHAR(255) NOT NULL,
ContentType NVARCHAR(100) NOT NULL,
ImageData VARBINARY(MAX) NOT NULL, -- SQL 2005+ 建議用此型別
UploadedAt DATETIME DEFAULT GETDATE()
);
public void SaveImage(string fileName, string contentType, byte[] imageBytes)
{
const string sql = "INSERT INTO Images (FileName, ContentType, ImageData) VALUES (@fn, @ct, @data)";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@fn", fileName);
cmd.Parameters.AddWithValue("@ct", contentType);
cmd.Parameters.AddWithValue("@data", imageBytes);
conn.Open();
cmd.ExecuteNonQuery();
}
}
public void GetImage(int imageId, HttpResponse response)
{
const string sql = "SELECT ContentType, ImageData FROM Images WHERE ImageID = @id";
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@id", imageId);
conn.Open();
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
response.ContentType = reader.GetString(0);
response.BinaryWrite((byte[])reader.GetValue(1));
}
}
}
}
FILESTREAM 文件群組的資料庫。VARBINARY(MAX) FILESTREAM NULL 欄位與 ROWGUIDCOL 唯一識別碼欄位。PathName() 取得 Win32 路徑,直接以檔案串流讀寫,繞過 T-SQL 協定層。DBCC CHECKDB 驗證 LOB 頁面完整性。