萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

SQL Server 分組取前 N 筆:IN 子查詢 vs ROW_NUMBER() 兩大寫法效能對決

需求:依多欄位分組,取每組前 N 筆 (通常 N=1)。提供兩種標準寫法並分析適用場景。

方法 1:IN + 子查詢 (適用單鍵、小資料量)

SELECT a.*
FROM table1 a
WHERE a.column1 IN (
  SELECT MAX(column1)
  FROM table1
  GROUP BY a.column2, column3
);
  • 直觀易懂,但子查詢無法直接參考外層別名 a.column2 (需重寫為關聯子查詢或 JOIN)。
  • 優化器易轉為 Semi Join,但大資料量時 IN 列表膨脹效能劣化。

方法 2:ROW_NUMBER() 視窗函數 (標準解、支援複雜分組與排序)

WITH ranked AS (
  SELECT
    NYR, QYZX_DM, FXSP_XH, SPBM_DLJ, WBSP_GG, JGLX, JZJG, MAX(SJGX_SJ),
    ROW_NUMBER() OVER (PARTITION BY NYR ORDER BY NYR) AS rn
  FROM WD_O_T_IC_SPSJ_FX
  GROUP BY NYR, QYZX_DM, FXSP_XH, SPBM_DLJ, WBSP_GG, JGLX, JZJG
)
SELECT *
FROM ranked
WHERE rn = 1;

修正:原文 WHERE rowno=1 置於 CTE 內部會報錯,必須在外層篩選。

效能對比與選擇指南

維度IN 子查詢ROW_NUMBER()
可讀性簡單分組佳通用、支援多欄排序
索引利用依賴 MAX() 索引掃描需 (PARTITION BY, ORDER BY) 複合索引
大資料量易產生大量邏輯讀單次掃描 + 排序,較穩定
取前 N (N>1)極難寫直接 WHERE rn <= N
相容性所有版本SQL Server 2005+

最佳實踐

  1. 預設採用 ROW_NUMBER(),彈性最高。
  2. 建立覆蓋索引:INDEX (partition_cols, order_cols) INCLUDE (select_cols) 避免 Key Lookup。
  3. 若分組鍵基數極大 (如用戶 ID),考慮應用層分頁或 TOP 1 WITH TIES 替代。
copyright © 萬盛學電腦網 all rights reserved