[MySQL] 使用索引覆蓋優化業務查詢

一、

在MySQL表中,有一項無法忽略的部分,那就是索引——因爲它直接或間接的決定了業務查詢的時間複雜度。一個差的索引,會導致SQL操作需要掃描全表,來查出符合條件的數據行,這當然是一個悲劇。我們有必要,但也很容易去避免以下這種情況的發生,只要針對業務查詢建對應的索引就可以了。

但是,只需要建出對應的索引就可以了嗎?當然是不夠的,核心操作業務如果需要的字段很少,通過索引覆蓋,性能可以達到一個質的飛躍。

二、

在最近涉及的業務當中,有一個比較簡單的點贊服務。模塊維護人當時的建表是符合常理的:

CREATE TABLE `user_like` (
  `item_id` bigint(20) NOT NULL,
  `user_id` bigint(20) NOT NULL,
  `insert_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  KEY (`user_id, item_id`),
  KEY (`user_id, insert_time`),) 
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 

由於業務需求主要集中在兩項:

1. 查看用戶是否對這個東西點過贊:select count(1) from user_like where user_id=xx and item_id=xx;

2. 查詢用戶的歷史點贊列表:select * from user_like where user_id=xx order by insert_time desc;

咋一看這兩個索引完美的契合了業務需求,但是實際上呢?

由於第2項業務在該產品中頻繁的觸發,即使有緩存還是有大量的SQL操作,雖然觸發索引KEY (user_id, insert_time)找到了對應的記錄,但是仍然需要讀取磁盤來查找這條索引對應的item_id字段,造成了一個龐大的開銷。

解決辦法就是將其改爲KEY (user_id, insert_time, item_id),即保留了user_id爲某值且按insert_time排序的查詢需求,又在索引中保留有item_id。這樣第二項業務需求的查詢,就被索引“覆蓋了”。而單純只查詢索引的數值,基本上只需要通過內存中的緩存,因此減少了大量打到磁盤的I/O。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章