MySQL索引二

序言

在上一篇文章中主要講了索引的底層實現。主要討論了爲什麼加了索引以後,數據庫的查詢效率會加快?底層怎麼實現的?這個問題。
那麼本文主要想討論下以下幾個問題

  1. 怎麼建立合適索引,建立索引有哪些需要規避的要點?
  2. 爲什麼有時候建立了索引也沒啥子用?
    以下是自己最近學習和使用的一些想法,希望大家可以互相交流,反正是技術交流哈哈。

首先拋出兩個語句乾貨。大家可以先去自己的數據庫執行檢查下。

– 查詢冗餘索引,看看是否有累贅索引

SELECT * from sys.schema_redundant_indexes;

– 查詢從未被使用到的索引,用都沒用過的,留着做啥。

SELECT * from sys.schema_unused_indexes;

怎麼建立合適索引,建立索引有哪些需要規避的要點

    首先我們要知道,索引並不是越多越好。雖然索引用的很爽。
    因爲底層是B+樹結構,我們在增,刪,改操作中都會對B+樹結構進行調整。
    所以索引過多也會影響此類操作。主要考慮在where和order by 後面涉及的列建立索引。
    同時,由於一條mysql在執行的時候,如果有多個索引命中,最終只能選擇其中一個索引。

所以個人見解:

要點一:複合索引和單列索引相比,應優先使用複合索引。

	針對建立複合索引之前,需要先做一個調研把哪個字段作爲最左前綴。
	調研可以從這幾個方面去判斷
	1.有哪個字段是經常會使用到的,且大部分sql中都會有值。
	舉個例子:
	user表裏有id,name,age,address,sex等字段。
    調研發現多數sql中都使用到了name這個字段作爲查詢條件。因此可建立複合索引idx_name_age_address(name,age,address)
	此處使用到的是mysql裏最常見的最左原則。爲什麼會有這個原則,和底層原理有關,在上一篇文章中也敘述了。
	2.字段長度小的列放在左側。因爲字段長度小,每一頁能存儲的數據量就越大,IO性能越好,也就是越快找到目標數據。
	3.如果創建的複合索引中某個字段中的值都是不同的,那麼他的數據區分度就高,走索引效率就非常明顯,考慮放在左側。
	這種複合索引比建立單列索引實用的多。

要點二:值比較稀少的列不建議使用索引

    比如上面例子中的sex字段。換句話說,建了索引也對查詢效率起不了作用。那麼爲啥會有這種論斷。
	因爲系統在執行一條sql的時候,會進行預測走這個索引和全表掃描哪個掃描的行數少。掃描行數越少,I/O操作次數越少。
	而我們走索引的時候,會通過sex這個索引先查到主鍵索引,再通過主鍵索引來查找數據。也就是會走兩次索引。也就是回表。
	系統通過索引的區分度來判斷,索引上不同的值越多,這個基數越大,那麼走索引查詢越有優勢。
    如果我們業務需要強制走某個索引查詢的話。可以使用select * from user force idx(age) where address = '中國'

要點三:儘量建立覆蓋索引

所謂覆蓋索引就是此索引覆蓋所有需要查詢的字段的值。尤其是查詢頻繁的語句,優先考慮覆蓋索引。上述例子中
	建立了複合索引idx_name_age_address(name,age,address)
	查詢語句:select id,name from user where name = '張三' and age = '20' and address = '中國'
	因爲B+樹的葉子節點存儲的是主鍵+列值,最終還是要回表,就會比較慢。但覆蓋索引要查詢出的列和索引是對應的,不需要做回表操作。
	我們往往會因爲偷懶或者想讓sql能夠複用,而使用select * from 的寫法。但這種無法使用覆蓋索引,也會消耗更多的CPU和IO

判斷建立的索引是否有效

要點一:判斷是否符合了最左前綴原則。

以上述例子中爲例:
	建立了複合索引idx_name_age_address(name,age,address)
	查詢語句:select * from user where  age = '20' and address = '中國'  
	此語句因爲最左前綴爲name,但是name沒有作爲條件查詢,無法使用索引。

要點二:查看where 子句左邊是否有進行函數,算術運算或者其他表達式運算

    select * from user where  age+1 = 20  -- 不能使用索引
    select * from user where  age = 20 -1 -- 能使用索引

要點三:儘量避免在WHERE子句中使用!=或<>操作符,將打算加索引的列設置爲 NOT NULL。否則將導致引擎放棄使用索引而進行全表掃描。

要點四:查詢語句有多個索引,數據庫選錯索引。

數據庫使用採樣的方式來預測各個索引的基數。既然是採樣,就有可能失誤。
若系統判斷當前索引基數過小,就不走索引,直接全表掃描。
所以不要對每個單列建立索引。索引需要的是有效,而不是多。

要點五:聯合索引的第一個索引使用了範圍查找導致失效

以上述例子中爲例:
	 建立了複合索引idx_name_age_address(name,age,address)
	查詢語句:select * from user where  name in ('張三',‘小敏’) and age = '20' and address = '中國'  
	在此sql中,name字段會用到索引,但是後面的age和address索引失效。
    因爲一個 SQL 只能利用複合索引中的一列進行範圍查詢。
	所以如果有範圍查詢的字段可以放在複合索引的右邊。不要使用not in 
	not in 通常會讓索引失效,可以用left join 或者 not exist 替代。

要點六:排查是否使用了子查詢

儘量不使用子查詢,可用join替代。
因爲子查詢的結果集會存儲在臨時表中,而臨時表是沒有索引的。同時也會消耗過多的CPU和IO。也是慢sql的一部分原因。

總結

    其實mysql使用B+樹作爲自己的數據結構,它是非常強大的。千萬數據量的大表,如果索引能夠使用的合適,也完全能夠支撐。
索引的重要性不言而喻,甚至在做開發設計評審時,索引也應該作爲數據庫設計裏重要的一項進行評審。
如果文中有說的不正確的地方,希望大家能夠互相交流,一起進步。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章