SQL 效能優化無銀彈,但遵循核心原則可解決 80% 以上效能問題。本文提煉五大黃金法則,附反面教材與正確範例,涵蓋查詢重寫、介面選擇、批次處理、索引策略、欄位設計。
-- ❌ 反模式:迴圈查詢 (N+1)
Set rsBooks = conn.Execute("SELECT * FROM Books")
Do While Not rsBooks.EOF
Set rsAuthors = conn.Execute("SELECT Name FROM Authors WHERE AuthorID=" & rsBooks("AuthorID"))
Response.Write rsBooks("Title") & " - " & rsAuthors("Name") & "
"
rsBooks.MoveNext
Loop
-- ✅ 正解:單一 JOIN 查詢
Set rs = conn.Execute("
SELECT B.Title, A.Name
FROM Books B
INNER JOIN Authors A ON A.AuthorID = B.AuthorID")
Do While Not rs.EOF
Response.Write rs("Title") & " - " & rs("Name") & "
"
rs.MoveNext
Loop
原理:減少網路往返、編譯開銷、鎖爭用;優化器可全域規劃最佳連接順序與演算法。
-- ❌ 反模式:Recordset 更新 (鎖持久、游標開銷)
rs.Open "SELECT * FROM Authors WHERE AuthorID=17", conn, adOpenKeyset, adLockOptimistic
rs("Name") = "Karl Karlsson"
rs.Update
-- ✅ 正解:直發 UPDATE (自動交易、最短鎖持有)
conn.Execute "UPDATE Authors SET Name='Karl Karlsson' WHERE AuthorID=17"
-- JScript 範例
var sql = "";
sql += "SET XACT_ABORT ON; BEGIN TRAN; ";
sql += "INSERT INTO Orders(OrdID,CustID,OrdDat) VALUES('9999','1234',GETDATE()); ";
sql += "INSERT INTO OrderRows(OrdID,OrdRow,Item,Qty) VALUES('9999','01','G4385',5); ";
sql += "INSERT INTO OrderRows(OrdID,OrdRow,Item,Qty) VALUES('9999','02','G4726',1); ";
sql += "COMMIT TRAN; SET XACT_ABORT OFF; ";
conn.Execute(sql);
關鍵:SET XACT_ABORT ON 確保任一陳述式失敗整批回滾,維持一致性。
OrderDate)INCLUDE 查詢所需所有欄位,避免書籤查找REBUILD/REORGANIZE + UPDATE STATISTICSsys.dm_db_index_usage_stats 找出未使用索引果斷刪除| 反模式 | 問題 | 優化 |
|---|---|---|
| CHAR(255) 存 20 字元 | 固定佔用 255 Bytes,50k 列浪費 12MB | VARCHAR(50) |
| TEXT/NTEXT 大欄位 | 行外儲存、無法線上索引、已棄用 | VARCHAR(MAX) / NVARCHAR(MAX) |
| FLOAT 存金額 | 精度誤差 | DECIMAL(18,4) / MONEY |
| DATETIME 只存日期 | 浪費 4 Bytes | DATE (SQL 2008+) |
效能優化是持續工程,而非一次專案。建立基準、監控趨勢、針對性修正,方能長治久安。