首頁 > 軟體

MySQL索引優化之適合構建索引的幾種情況詳解

2022-07-29 14:04:23

結論

  1. 在where後面的過濾欄位上建立索引(select/update/delete後面的where都是適用的),使用索引加快過濾效率,不用進行全表掃描
  2. 在具有唯一要求的欄位上新增唯一索引,加快查詢效率,查到即可直接返回
  3. group by或者order by後面的欄位新增索引,由於索引是排好序的,所以建立索引就等同於在查詢之前已經是排好序了(這裡需要注意建立的聯合索引建立中欄位的順序,可以結合具體案例場景7進行學習)
  4. 在DISTINCT(去重欄位)後面的欄位新增索引,由於建立了索引,那麼相同的資料就是挨在一起的,所以就可以進行快速的去重操作,否則可能就需要將相同的資料找出來在進行去重操作
  5. 在多表連線join的時候在連線的欄位上建立索引(小表驅動大表)
  6. 取字串一定字首建立索引(不是用整個字串作為索引,否則將會佔用太大的空間)
  7. 在頻繁使用的列上建立索引(可以建立聯合索引,同時最頻繁使用的欄位應該在聯合索引的最左側,最左側原則)
  8. 在區分度高的列上建立索引(主鍵的區分度最高,因為所有的鍵都是唯一的)

建立索引的場景

場景一:在where欄位後面的欄位建立索引

-- 描述:當where中有多個條件需要進行匹配的時候,那麼可以建立聯合索引,這樣所有的條件都可以使用索引,大大提高了檢索的效率
select * from student_info where student_id = 1;
-- 當然資料量比較大的時候給where後面的欄位新增索引
create index student_id_index on student_info (student_id)

未新增索引前,耗費0.383秒,基本遍歷整個表

新增索引後,耗費0.001秒,使用了索引(但是建立索引的時候會耗費一定時間)

在頻繁的查詢的業務中可以對where篩選的欄位建立索引,如果where篩選的欄位有多個還可以建立聯合索引

場景二:在具有唯一性約束的欄位上建立唯一索引(查詢到目標即可返回不用繼續查詢)

select * from student_info where id = 1001;
-- 因為學號是唯一的,所以可以在學號這個欄位上新增唯一所用
create index id_unique on student_info(id);

具有唯一性約束的欄位上就可以建立唯一索引,雖然建立了唯一索引對insert操作有一定的影響(需要判斷新增的資料是否已經在表中),但是建立唯一索引對於查詢的效率是顯著提升的,例如上面的例子,因為建立了唯一索引,一旦查詢到id為1001的學生資訊之後就不需要判斷資料庫中是否還有id等於1001的學生(只有唯一一份),直接返回資訊即可,如果沒有建立索引,那麼就需要全表掃描

場景三:經常group by和order by的欄位上建立索引(因為索引本身就是排好序的,相當於查詢之前就已經進行了排序)

select * from student_info order by name;
-- 這裡就可以給name欄位進行索引的新增
select * from student_info group by class_id;
-- 這裡就可以給class_id欄位新增索引

建立索引前,耗時0.501秒,使用的是所有資料在記憶體中排序

建立索引後,耗時0.01秒

場景四:在DISTINCT後面的欄位新增索引(索引已經將相同的欄位排好序,去重效率更高)

select distinct(student_id) from student_info;
-- 這裡就可以根據student_id欄位建立索引
create index student_id_index on student_info;

建立了索引,那麼預設就是按照索引欄位的升序排列的,那麼相同值的欄位也就排列在一起了,那麼去重也就變得簡單、高效

場景五:在join多表連線大表中的連線欄位建立索引

SELECT s.course_id,NAME,s.student_id,c.course_name
FROM student_info s JOIN course c
ON s.`course_id` = c.`course_id`
WHERE NAME = 'xiaoyuanhao';
-- 根據大表驅動小表的原則需要在student_info表的course_id欄位上建立索引

沒有建立索引之前,耗時0.697s,沒有使索引

建立索引後,使用了索引,耗時0.003s

小表驅動大表:

通過對小表進行逐一遍歷,同時在大表中的連線欄位建立索引即可加快查詢,本案例中,每次取出課程表中course_id和學生表中學生的course_id進行連線操作,在學生表中對course_id建立索引即可

場景六:使用字串的字首建立索引

create table shop(address varchar(120) not null);
alter table shop add index(address(12));
--這裡只是對錶中的address的前12個字元建立了索引,而不是整個字串建立索引

字首建立索引的原因:

  • 由於有些字串很長,如果為整個字串建立索引,那麼索引將佔用很大的空間
  • 由於需要儲存整個字串,那麼資料項就會很大,那麼索引樹的深度就會加深,檢索速度下降
  • 雖然可能出現在索引中兩個字串相同,但是再根據主鍵進行回表操作效率依然比較高

如何確定字首索引中字首的長度呢?(也就是如果字首的長度太短,那麼索引的區分度就很低,從多個字串擷取的字首資料可能都是一樣的,但是如果字首索引的字首過長,那麼字首索引的優點就消失了)

引入了區別度的概念,select count(distinct left(索引欄位,字首索引長度) / count(*) from xxx),該值越接近1,那麼區分度就越明顯,那麼該索引長度就是所求的字首索引長度

場景七:在頻繁使用的列上建立索引或聯合索引(頻繁使用的欄位應該在索引的左側)

select * from xiaoyuanhao where age = 18;
select * from xiaoyuanhao where age = 19 and sex = 'man';
select * from xiaoyuanhao where age = 10 and sex = 'man' and password = '123456';
-- 在這裡實際上就可以建立age,sex,password的聯合索引,只需要建立一個索引,這三個查詢都是可以使用的
create index age_sex_password_index on xiaoyuanhao(age,sex,password);
select * from student_info group by class_id order by name;
-- 在這裡可以建立class_id和name的聯合索引,但是一定要注意索引的順序,一定是要class_id在前,name在後,因為在select語句中執行的順序是先group by 之後才是 order by 索引如果索引的欄位順序是相反的,那麼就無法使用索引
create index class_id_name_index on student(class_id,name);

索引建立需要符合順序的原因:

索引欄位的順序如果是錯誤的,那麼索引就會失效,因為索引實際上是排好序的,如果索引建立的時候是現根據name排好序之後在根據class_id進行排序,那麼在面對需要先根據class_id排序再根據name排序的業務就無法進行使用

補充:

在select * from xxx where age = 19 and sex = ‘man’ and password = '123456’這裡索引建立的順序不一定是(age,sex,password)因為在實際執行的過程中,優化器會優化執行步驟會按照索引的順序進行查詢,但是group by 和 order by的執行順序是無法改變的,索引必須嚴格的按照順序建立索引,否則索引失效

小結

  • 以上是適合建立索引的幾種情況,但是實際上是否會使用索引,還是由優化起決定的,優化器會根據具體的查詢以及資料量進行分析決定的
  • 當建立了索引但是卻沒有使用的時候有可能是資料索引失效或者經過優化器分析沒有必要使用索引
  • 建立了索引也是存在失效的可能,下面的文章關於索引失效的案例,可以一起學習討論:索引優化:MySQL索引優化之不適合構建索引及索引失效的幾種情況詳解

到此這篇關於MySQL索引優化之適合構建索引的幾種情況詳解的文章就介紹到這了,更多相關MySQL索引優化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com