More or less, less is more

駱勁成
iCHEF
Published in
3 min readJun 10, 2020

資料庫搜尋都有用索引怎麼還是跑不完?

長話短說

資料多元性低的資料庫欄位(例如 Boolean)請考慮不要為它單獨建立索引,它很可能會在資料量大時導致資料庫查詢非常慢。

詳細解釋

資料庫索引的作用就像我們去圖書館借書的索書號,可以讓我們在相對短的時間內從眾多藏書中找到自己要的,資料庫索引就是這麼重要,只要這個欄位會被排序或查詢,就讓人下意識的覺得需要為它建立索引。

多元性差(Low Cardinality)的欄位在資料量大時,可能導致資料庫在查詢時選擇錯的索引,不囉嗦,範例:

SELECT 
*
FROM
votes
WHERE
vote_at > '2020-06-06 08:00:00+08'
AND vote_at < '2020-06-06 08:10:00+08'
AND agree = false

假設:
vote_at, agree都有各自建立索引
— 資料中 96.8 % agree = true
— votes 這個 table 資料筆數過億

在查詢 agree = false 時,agree這個索引 96.8 % 的資料都不是這個查詢的目標,但資料庫還是可能選擇耗費大量效能在使用這個過億長度的索引,篩出剩餘的 3.2 % 資料後才繼續其他條件查詢。

一個簡單的解法就是把agree這個索引刪除,資料庫就會優先使用其他索引篩選(index scan) ,篩選下已相對少的結果再對 agree 做篩選(seq scan)。

不想直接刪除索引,也可利用 OFFSET 0 的語法,先試跑看看優先使用其他索引的查詢:

SELECT
*
FROM (
SELECT
*
FROM
votes
WHERE
vote_at > '2020-06-06 08:00:00+08'
AND vote_at < '2020-06-06 08:10:00+08'
OFFSET 0
) _
WHERE
agree = false

想確認你的索引多元性如何嗎?
MySQL 可以 SHOW INDEXES FROM your_table 查看 cardinality 欄位的值,或是就直接 SELECT COUNT(DISTINCT(your_column)) FROM your_table

多元性就是這麼重要,不管在社會上還是資料庫。

索引能幫助我們,也可以毀了我們;就像人民可以給你權力,也可以把它收回。珍惜它,別濫用它。

--

--