本文 AI 產出,尚未審核

MySQL 課程 – SELECT 查詢語法

主題:ORDER BY 排序


簡介

在日常的資料查詢工作中,排序是最常見也是最重要的需求之一。無論是顯示商品清單、列出使用者排行榜,或是產生報表,正確的排序都直接影響使用者的閱讀體驗與決策依據。

MySQL 提供的 ORDER BY 子句讓我們可以依照一或多個欄位,以升冪 (ASC) 或降冪 (DESC) 的方式排列結果。雖然語法看似簡單,但在實務上卻常伴隨著效能、字元編碼、NULL 處理等隱藏的陷阱。掌握 ORDER BY 的核心概念與最佳實踐,能讓你的查詢既正確高效

本篇將從概念說明、實作範例、常見問題與最佳做法,逐步帶你深入了解 ORDER BY,適合剛入門的初學者,也能為有一定基礎的開發者提供進階的觀點。


核心概念

1. 基本語法

SELECT 欄位1, 欄位2, ...
FROM 資料表
WHERE 條件
ORDER BY 排序欄位1 [ASC|DESC], 排序欄位2 [ASC|DESC], ...;
  • ASC 為預設值,代表 升冪(由小到大、由 A 到 Z)。
  • DESC 代表 降冪(由大到小、由 Z 到 A)。
  • 可以同時指定多個欄位,MySQL 會依序比較,第一個欄位相同時才會比較第二個,以此類推。

小技巧:若只想排序卻不需要返回排序欄位本身,可在 SELECT 中省略該欄位,只在 ORDER BY 中保留。


2. 排序依據的資料型別

資料型別 排序方式 注意事項
數值 (INT, DECIMAL, …) 直接比較大小 無需額外處理
日期/時間 (DATE, DATETIME, TIMESTAMP) 依時間先後排序 時區設定會影響結果
字串 (CHAR, VARCHAR, TEXT) 依字元編碼排序 collation(字元集排序規則)影響,中文排序常用 utf8mb4_unicode_ci
ENUM / SET 按定義順序排序 仍屬於字串類型,建議使用 FIELD() 取得自訂順序

3. NULL 的排序行為

  • 預設NULL 被視為 最小值,在 ASC 時排在最前、在 DESC 時排在最後。
  • 若想改變此行為,可使用 ORDER BY ... IS NULLCOALESCE() 來自訂排序。
-- 把 NULL 放到最後(升冪)
SELECT name, score
FROM students
ORDER BY score IS NULL, score ASC;

4. 使用索引提升排序效能

  • ORDER BY 的欄位與 WHERE 條件中的欄位相同,且符合 索引的左前綴,MySQL 可以直接利用索引返回已排序的資料,省去額外的排序(filesort)步驟。
  • 複合索引(INDEX(col1, col2))能同時支援 ORDER BY col1, col2
  • 避免ORDER BY 前使用不必要的 SELECT *JOIN 產生大量中間結果,會迫使 MySQL 進行磁碟排序。

5. 進階排序技巧

技巧 語法 說明
自訂排序順序 ORDER BY FIELD(col, 'A','B','C') 依指定的列舉值排序,常用於狀態欄位
多欄位混合升降 ORDER BY col1 ASC, col2 DESC 第一欄升冪、第二欄降冪
排序計算結果 ORDER BY (price * quantity) DESC 直接對表達式排序
字串長度排序 ORDER BY CHAR_LENGTH(name) ASC 依字串長度排序
隨機排序 ORDER BY RAND() 常用於抽樣顯示,注意效能

程式碼範例

以下示範 5 個實務上常見的 ORDER BY 用法,均以 MySQL 8.0+ 為基礎,並加入完整註解說明。

範例 1:基本升冪與降冪排序

-- 依商品價格由低到高排列
SELECT product_id, product_name, price
FROM products
ORDER BY price ASC;      -- ASC 可省略

-- 依庫存數量由高到低排列
SELECT product_id, product_name, stock
FROM products
ORDER BY stock DESC;     -- 降冪

範例 2:多欄位混合排序

-- 先依類別 (category_id) 升冪,類別相同時依上架日期降冪
SELECT product_id, product_name, category_id, created_at
FROM products
ORDER BY category_id ASC, created_at DESC;

範例 3:自訂狀態排序(FIELD)

-- 訂單狀態的自訂順序:'pending' > 'processing' > 'shipped' > 'completed'
SELECT order_id, status, order_date
FROM orders
ORDER BY FIELD(status,
               'pending',
               'processing',
               'shipped',
               'completed') ASC;

範例 4:將 NULL 放最後(升冪)

-- 顯示會員的最後登入時間,NULL 表示從未登入,放到最底部
SELECT member_id, last_login
FROM members
ORDER BY last_login IS NULL, last_login ASC;

範例 5:使用索引加速排序

-- 假設已有複合索引 (category_id, price)
CREATE INDEX idx_cat_price ON products (category_id, price);

-- 依類別與價格排序,MySQL 可直接走索引,不會產生 filesort
SELECT product_id, product_name, category_id, price
FROM products
WHERE category_id IN (1,2,3)
ORDER BY category_id ASC, price DESC;

備註:在開發環境中可使用 EXPLAIN 觀察是否真的走索引,若出現 Using filesort 表示仍需額外排序,可能是因為索引不符合排序需求或有額外的 SELECTJOIN 影響。


常見陷阱與最佳實踐

陷阱 說明 解決方案
忘記指定方向 ORDER BY col 預設升冪,若實際需求是降冪,結果會相反。 明確寫 ASCDESC,降低誤解。
字元編碼不一致 utf8 vs utf8mb4、不同 collation 會導致排序結果不符合預期(特別是中文)。 統一資料庫與欄位的 CHARACTER SETCOLLATE,如 utf8mb4_unicode_ci
大量資料排序未使用索引 大表直接 ORDER BY 會觸發磁碟排序,效能嚴重下降。 建立適當的索引、限制返回列數 (LIMIT)、或先篩選 (WHERE) 再排序。
使用 SELECT * 搭配 ORDER BY 不必要的欄位會增加 I/O,且可能破壞索引排序的使用。 只挑選需要的欄位,減少資料量。
ORDER BY RAND() 隨機排序在大資料集上會把整表載入記憶體,極度耗資源。 若只需要抽樣,可使用 LIMIT 搭配子查詢或 TABLESAMPLE(MySQL 8.0+)等方法。
NULL 排序不符合需求 預設把 NULL 視為最小值,導致意外的排序結果。 使用 IS NULLCOALESCE() 或自訂排序式處理。

最佳實踐清單

  1. 明確寫出方向ORDER BY col DESC 而非省略。
  2. 盡量使用索引:檢查 EXPLAIN,確保不出現 Using filesort
  3. 限制結果筆數:配合 LIMIT,尤其在分頁查詢時。
  4. 統一 Collation:中文排序建議使用 utf8mb4_unicode_ciutf8mb4_0900_ai_ci
  5. 避免在大表直接使用 ORDER BY RAND(),改用其他抽樣技巧。
  6. 考慮 NULL 處理:根據需求自行決定 NULL 的位置。
  7. 分頁時使用穩定排序:加入唯一鍵(如 id)作為最後的排序欄位,避免同分頁間資料重複或遺漏。

實際應用場景

場景 需求 ORDER BY 實作
商品列表 按價格由低到高、同價位依上架時間最新排序 ORDER BY price ASC, created_at DESC
會員排行榜 依積分降冪,積分相同時依註冊日期升冪 ORDER BY points DESC, register_date ASC
訂單管理系統 先顯示「未處理」狀態,再顯示「已處理」;每個狀態內依下單時間最新排序 ORDER BY FIELD(status, 'pending','processing','shipped','completed'), order_date DESC
報表匯出 依部門、年度、薪資降冪產出 Excel ORDER BY department ASC, year ASC, salary DESC
分頁搜尋 大量資料的分頁,需要穩定且可預測的排序 ORDER BY created_at DESC, id DESC LIMIT 20 OFFSET 0

這些案例展示了 排序 在不同業務需求中的核心角色,透過正確的 ORDER BY 設計,不僅提升使用者體驗,也能大幅降低資料庫負載。


總結

ORDER BY 是 MySQL 中最常用、也是最具影響力的子句之一。掌握以下要點,即可寫出 正確、可讀、效能佳 的排序查詢:

  1. 明確指定排序方向(ASC / DESC)。
  2. 了解資料型別與 collation,避免字元排序錯誤。
  3. 妥善處理 NULL,確保結果符合業務邏輯。
  4. 善用索引,減少 filesort 帶來的 I/O 壓力。
  5. 遵循最佳實踐(限制欄位、分頁、避免 RAND() 等),讓查詢在大資料量下仍保持高效。

透過本篇的概念說明、實作範例與最佳實踐,你已具備在日常開發與資料分析中運用 ORDER BY 的完整能力。未來只要面對更複雜的排序需求,記得回顧本文的「多欄位混合排序」與「自訂排序」技巧,配合適當的索引與測試,即可輕鬆解決。祝你在 MySQL 的世界裡查詢順手、效能滿分!