首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 索引結構與查詢優化(二):SARG 實戰、SQL 寫法陷阱與效能實測

     編輯:關於SqlServer

深度實測:SQL Server 查詢優化器、SARG 機制與高效 SQL 寫法

查詢優化器自動優化原理

SQL Server 內建「查詢分析優化器」,自動計算 WHERE 條件選擇最佳索引。**條件順序不影響效能**,優化器會重新排序。但理解 SARG(Search ARGument)機制對編寫高效 SQL 至關重要。

SARG 定義與標準形式

欄位名 運算子 <常數或變數>
或
<常數或變數> 運算子 欄位名

符合 SARG 可利用索引快速定位;不符合需全表掃描逐行判斷。

11 大實戰 SARG 陷阱與效能實測

1. LIKE 通配符位置決定索引生死

  • name LIKE '張%' → SARG,索引有效
  • name LIKE '%張' → 非 SARG,前置 % 導致索引失效

2. OR 引發全表掃描

  • Name='張三' AND 價格>5000 → SARG
  • Name='張三' OR 價格>5000 → 非 SARG,全表掃描

3. 否定運算子與函數破壞 SARG

典型非 SARG:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE、函數運算(ABS(價格)<5000)

特例:WHERE 價格*2>5000 可被轉換為 WHERE 價格>2500 視為 SARG,**但不建議依賴**,無法保證完全等價。

4. IN 等價 OR,同樣導致全表掃描

SELECT * FROM table1 WHERE tid IN (2,3)
-- 等同於
SELECT * FROM table1 WHERE tid=2 OR tid=3

即使 tid 有索引也會失效。

5. 減少使用 NOT

6. EXISTS 與 IN 效能完全相同

實測(pubs 資料庫,STATISTICS IO):

-- IN 版本
SELECT title, price FROM titles 
WHERE title_id IN (SELECT title_id FROM sales WHERE qty>30)
-- sales: 掃描 18,邏輯讀 56 | titles: 掃描 1,邏輯讀 2

-- EXISTS 版本
SELECT title, price FROM titles 
WHERE EXISTS (SELECT * FROM sales WHERE sales.title_id=titles.title_id AND qty>30)
-- sales: 掃描 18,邏輯讀 56 | titles: 掃描 1,邏輯讀 2

I/O 統計完全一致。NOT EXISTS / NOT IN 同理。

7. CHARINDEX() 與前置 % LIKE 效能無差異

-- CHARINDEX:7秒,掃描 4,邏輯讀 7155
SELECT * FROM tgongwen WHERE CHARINDEX('刑偵支隊', reader)>0 AND fariqi>'2004-5-5'

-- LIKE %:7秒,掃描 4,邏輯讀 7155
SELECT * FROM tgongwen WHERE reader LIKE '%'+'刑偵支隊'+'%' AND fariqi>'2004-5-5'

8. UNION 不絕對優於 OR(關鍵發現)

一般情況 UNION 較快:

-- OR:68秒,邏輯讀 404008
SELECT * FROM Tgongwen WHERE fariqi='2004-9-16' OR gid>9990000

-- UNION:9秒,邏輯讀 67489
SELECT * FROM Tgongwen WHERE fariqi='2004-9-16'
UNION
SELECT * FROM Tgongwen WHERE gid>9990000

**但當 OR 兩側查詢同一欄位時,UNION 反而較慢:**

-- OR:6423ms,掃描 2,邏輯讀 14726
SELECT * FROM Tgongwen WHERE fariqi='2004-9-16' OR fariqi='2004-2-5'

-- UNION:11640ms,掃描 8,邏輯讀 14806
SELECT * FROM Tgongwen WHERE fariqi='2004-9-16'
UNION
SELECT * FROM Tgongwen WHERE fariqi='2004-2-5'

原因:UNION 需合併去重,增加額外排序/雜湊開銷。

9. 欄位提取遵循「需多少、取多少」

SELECT TOP 10000 gid, fariqi, reader, title ... -- 4673ms
SELECT TOP 10000 gid, fariqi, title ...          -- 1376ms
SELECT TOP 10000 gid, fariqi ...                 -- 80ms

每減少一欄位,速度顯著提升,幅度取決於欄位大小。

10. COUNT(*) 不比 COUNT(欄位) 慢

COUNT(*)       -- 1500ms
COUNT(gid)     -- 1483ms (主鍵)
COUNT(fariqi)  -- 3140ms
COUNT(title)   -- 52050ms

COUNT(*) 與 COUNT(主鍵) 速度相當,且比其他欄位快。引擎推測自動選最小欄位統計。

11. ORDER BY 聚集索引欄位效能最高

無 ORDER BY (fariqi 聚集索引)  -- 196ms
ORDER BY gid ASC (主鍵非聚集)   -- 4720ms
ORDER BY gid DESC               -- 4736ms

聚集索引排序快 3/10。小數據量差異明顯,大數據量(10萬+)差異縮小。

日期欄位精度對查詢速度影響測試

100萬筆:2004/1/1 後 50萬筆(2 個不同日期,精確到日);之前 50萬筆(5000 個不同日期,精確到秒)。

fariqi > '2004-1-1' ORDER BY fariqi  -- 6390ms
fariqi < '2004-1-1' ORDER BY fariqi  -- 6453ms

結論:日期含時分秒**不降低**查詢速度。

索引建立核心原則

  • 索引助查詢,但過多/不當導致系統低效(維護成本、碎片)
  • 建立「適當」索引體系,聚集索引選擇需精益求精
  • DBA 應多測試方案,找出最高效配置
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved