iT邦幫忙

2025 iThome 鐵人賽

DAY 8
3

https://ithelp.ithome.com.tw/upload/images/20250901/20177885FFCfdgKZlJ.png

當查詢結果時不只是單純讀取資料,而是還需要額外做轉換或運算時,效能可能會受到影響。但其實我們可以善用 Index,讓這些轉換在查詢前就先「準備好」,查詢的速度可能就會加快。

舉例來說,如果某個欄位在查詢時經常需要轉為小寫再比對,我們就可以在建立 Index 的時候,直接針對轉換後的小寫值建立 Index,讓查詢時不必每次都即時運算,這個稱為 Expression index。

例如,假如希望在查詢 quizzes 表中的 school_type 時,能夠忽略大小寫,並且都用小寫來查詢,可以直接將小寫的 school_type 建立成 Index:

CREATE INDEX quizzes_lower_school_type_idx ON quizzes (lower(school_type));

接著進行查詢時,我們可以看到它能夠直接使用到建立好的 Index:

EXPLAIN ANALYZE
SELECT * FROM quizzes WHERE lower(school_type) = 'elementary';

https://ithelp.ithome.com.tw/upload/images/20250808/20177885bCJBL7oyq8.png

一般 Index vs. Expression Index

我們來比較看看,不將小寫版本的值當作 Index,而是直接將原始的 school_type 欄位設為 Index 時的速度。先刪除原來的 Index:

DROP INDEX quizzes_lower_school_type_idx;

然後,重新建立 Index,不使用 lower() 函數:

CREATE INDEX quizzes_lower_school_type_idx ON quizzes(school_type);

再次查詢時,會發現他不會使用到 index 了!這是因為 lower() 會在比較前就改變了原本的值,導致沒辦法使用原本 B-Tree 內的值。

https://ithelp.ithome.com.tw/upload/images/20250808/201778850M8poT1ni2.png

多個欄位組合再轉換的 Index

有些情況下,查詢條件需要將多個欄位組合在一起,例如:

SELECT * FROM people WHERE (first_name || ' ' || last_name) = 'John Smith';

從上面的測試可以發現,就算把 first_namelast_name 這兩個欄位建立了 Index,這樣的查詢條件是沒辦法使用的到 Index 的。

-- 建立 table
CREATE TABLE people (
	id SERIAL PRIMARY KEY,
	first_name VARCHAR(255) NOT NULL,
	last_name VARCHAR(255) NOT NULL
);

-- 建立沒有組合過資料的 index
CREATE INDEX idx_people_name ON people (first_name, last_name);

-- 確認是否有使用到 index
EXPLAIN ANALYZE
SELECT * FROM people WHERE (first_name || ' ' || last_name) = 'book growth';

https://ithelp.ithome.com.tw/upload/images/20250808/20177885oUM46ZWxQM.png

因此為了提高查詢速度,我們可以將組合欄位 (first_name || ' ' || last_name) 本身設為 Index:

CREATE INDEX people_names ON people ((first_name || ' ' || last_name));

這樣再次查詢時,就可以發現搜尋因為能使用到 index 變快了!

https://ithelp.ithome.com.tw/upload/images/20250808/201778853B28orqNAH.png

不過要注意速度變快的原因,是因為轉換的步驟在 insert / update 的時候就先做完了,因此時間會分散在每次 insert / update 的時候,換來的是查詢的速度可以變得更快喔~

Indexes on expressions are useful when retrieval speed is more important than insertion and update speed.

重點回顧

  • Expression Index:當需要對欄位進行轉換處理(例如轉換為小寫或組合多個欄位)時,可以建立 Expression Index 來提高查詢效率。
  • Expression Index 因為轉換或組合的過程會在 insert / update 時完成,因此寫入的成本會增加,適合在查詢速度優先於寫入速度的情境下使用。

參考資料

https://www.postgresql.org/docs/current/indexes-expressional.html


上一篇
Day 7 - UNIQUE Index:確保資料唯一性
下一篇
Day 9 - Partial Index:只幫必要資料加 Index
系列文
PostgreSQL 效能優化 30 天挑戰:從 Index 到 Transaction 的深入探索9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言