SMALLINT 別用 INT;員工編號優於身分證字號SMALLINTSELECT * FROM Orders WHERE CustomerID LIKE 'D%'; -- 使用索引
SELECT * FROM Orders WHERE CustomerID LIKE '%D'; -- 不使用索引
SQL Server 2005+ 可按 Ctrl+L 檢視執行計畫驗證。
NOT、!=、<>、!>、!<、NOT EXISTS、NOT IN、NOT LIKE 易導致無法使用索引,建議改寫。
-- 差:函數運算導致索引失效
SELECT * FROM Orders WHERE DATEPART(yyyy, OrderDate) = 1996;
-- 優:範圍查詢利用索引
SELECT * FROM Orders WHERE OrderDate BETWEEN '19960101' AND '19961231';
-- 差:字串運算
SELECT * FROM Orders WHERE SUBSTRING(CustomerID, 1, 1) = 'D';
-- 優:LIKE 前綴匹配
SELECT * FROM Orders WHERE CustomerID LIKE 'D%';
資料依叢集索引順序儲存,包含該欄位的 BETWEEN、GROUP BY、ORDER BY 可提速。
複合索引第一欄位才適合作為過濾條件。
函數運算等同於運算/串接,可能導致索引失效。更嚴重的是:10 萬筆資料需呼叫函數 10 萬次,系統上線後效能問題逐漸浮現。
SELECT * FROM Orders WHERE CustomerID='VINET' AND Freight=32.3800; -- 使用索引
SELECT * FROM Orders WHERE CustomerID='VINET' OR Freight=32.3800; -- 全表掃描
SELECT * FROM Orders WHERE CustomerID='VINET'
UNION
SELECT * FROM Orders WHERE Freight=32.3800;
上半段用索引,下半段全表掃描,仍有改善。
為 830 筆資料產生流水號:
-- ROW_NUMBER() 窗口函數:2 ms
SELECT OrderID, ROW_NUMBER() OVER(ORDER BY OrderID) AS 編號 FROM dbo.Orders;
-- 傳統相關子查詢:170 ms(830 次全表掃描)
SELECT OrderID,
(SELECT COUNT(*) FROM dbo.Orders 內圈 WHERE 內圈.OrderID <= 外圈.OrderID) AS 編號
FROM dbo.Orders 外圈 ORDER BY 編號;
31,465 筆資料:
ROW_NUMBER():677 ms結論:能用 JOIN/窗口函數解決的,盡量避免相關子查詢。開發初期資料量小感受不到,上線後災難性後果。
DISTINCT、ORDER BY 額外運算成本UNION ALL 代替 UNIONEXEC dbo.mySP1 避免解析開銷避免 SELECT * 回傳全表再由前端篩選,浪費資料庫資源、Web Server 記憶體、網路頻寬。在 SQL/預存程序層完成過濾。