切換語言為:簡體
MySQL用了函式到底會不會導致索引失效

MySQL用了函式到底會不會導致索引失效

  • 爱糖宝
  • 2024-07-03
  • 2087
  • 0
  • 0

很多人認為,在使用函式後就無法使用索引。

這主要是因為索引是按照列值的原始順序組織和儲存的。當對列應用函式時(如數學運算、字串操作或日期函式等),函式會改變原始資料的值或格式,使得資料庫無法直接定位到這些經過函式轉換後的值。因此,資料庫不得不執行全表掃描,以確保能夠評估所有行上的函式操作,這導致查詢效能下降。

在 MySQL 8.0 之後,引入了函式索引,這改變了以往對函式使用索引的限制。

MySQL 8.0 引入了功能索引(Functional Indexes)的新特性,這種索引允許在建立時包含列上的表示式。這意味著可以對資料進行計算或轉換,並針對結果建立索引。即使在查詢中使用了函式操作,也可以利用這些索引來最佳化查詢效能。

功能索引不是直接在表的列上建立的,而是基於列的某個表示式建立的。這個表示式可以是簡單的數學運算,也可以是字串函式、日期函式等。一旦建立了功能索引,MySQL 在執行涉及該表示式的查詢時能夠使用這個索引,從而提升查詢效率。

使用方式

在 MySQL 8.0 中,您可以建立一個基於 first_namelast_name 合併後的表示式的功能索引,示例如下:

plCREATE INDEX full_name_index ON employees ((CONCAT(first_name, ' ', last_name)));


這個例子中,我們使用了 CONCAT 函式將 first_namelast_name 合併成一個全名,並在建立索引時使用了這個表示式 (CONCAT(first_name, ' ', last_name))。 這樣一來,即使在查詢中直接使用全名的合併結果,MySQL 也能夠利用 full_name_index 索引來最佳化查詢效能。

plSELECT * FROM employees WHERE CONCAT(first_name, ' ', last_name) = 'Pai daxing';


MySQL用了函式到底會不會導致索引失效

如上圖所示,執行計劃顯示我們成功利用了 idx_full_name索引!

因此,即使在查詢的 WHERE 子句中使用了 CONCAT 函式,我們依然能夠充分利用 idx_full_name 函式索引,從而有效提升了查詢的效率。

注意事項

函式索引雖然能夠顯著提高涉及索引表示式的查詢效能,但其建立可能增加資料插入、更新和刪除的成本,因為資料庫需要維護更多的索引資料。因此,在建立函式索引時需要謹慎,不能盲目使用。

使用函式索引時,必須仔細考慮和測試,以確保效能提升符合預期。

此外,在建立函式索引時,需要確保表示式是確定的,即對於給定的輸入值始終產生相同的輸出值。非確定性表示式不適合用於函式索引。

常見函式索引用法

給大家列舉一些常見的函式索引的使用。

字串處理

當您經常需要根據某個字串列的某部分進行查詢時,可以考慮使用函式索引。例如,如果您希望根據郵箱地址的域名部分查詢使用者,可以建立如下的函式索引:

plCREATE INDEX idx_email_domain ON users ((SUBSTRING_INDEX(email, '@', -1)));


這樣,當您查詢特定域名的郵箱時(例如 qq 郵箱),可以利用這個索引:

plSELECT * FROM users WHERE SUBSTRING_INDEX(email, '@', -1) = 'qq.com';


日期和時間處理

對於涉及日期和時間處理的查詢,函式索引也非常有用。假設您需要頻繁查詢基於訂單日期的年份或月份,可以建立如下的索引:

plCREATE INDEX idx_order_year ON orders ((YEAR(order_date))); 
CREATE INDEX idx_order_month ON orders ((MONTH(order_date)));


這允許您高效地查詢特定年份或月份的訂單:

plSELECT * FROM orders WHERE YEAR(order_date) = 2022; 
SELECT * FROM orders WHERE MONTH(order_date) = 12;


數學運算

如果查詢條件經常包含對數值列的數學運算,可以針對這些運算建立函式索引。例如,如果您希望根據產品折扣後的價格進行查詢,可以建立如下索引:

CREATE INDEX idx_discounted_price ON products ((price * (1 - discount_rate)));


然後,您可以高效地查詢特定範圍的折扣價格:

SELECT * FROM products WHERE price * (1 - discount_rate) BETWEEN 50 AND 100;


使用 JSON 函式

如果在 MySQL 中使用 JSON 資料型別,並且需要基於 JSON 屬性進行查詢,可以建立基於 JSON 函式的索引。例如,如果您有一個儲存 JSON 資料的列,並且希望根據 JSON 文件中的某個鍵進行查詢,可以建立如下索引:

plCREATE INDEX idx_json_key ON orders ((JSON_UNQUOTE(JSON_EXTRACT(order_info, '$.status'))));


這樣,您可以高效地查詢具有特定狀態的訂單:

plSELECT * FROM orders WHERE JSON_UNQUOTE(JSON_EXTRACT(order_info, '$.status')) = 'shipped';


大小寫不敏感的搜尋

如果您需要執行大小寫不敏感的字串搜尋,可以建立一個基於 LOWER()UPPER() 函式的索引:

CREATE INDEX idx_lower_case_name ON customers ((LOWER(name)));


這樣可以讓您執行大小寫不敏感的搜尋,同時不影響效能:

SELECT * FROM customers WHERE LOWER(name) = LOWER('John Doe');


在使用函式索引時,需要權衡索引的維護成本和效能提升。雖然函式索引可以顯著提升特定查詢的效能,但它們也會增加插入、更新和刪除操作的成本,因為資料庫需要維護更多的索引資料。因此,在實際應用中,建議僅對那些經常作為查詢條件的列和表示式建立函式索引。


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.