mysql 索引使用注意事項
原文地址 點選
文章目錄
MySQL 索引通常是被用於提高 WHERE 條件的資料行匹配時的搜尋速度,在索引的使用過程中,存在一些使用細節和注意事項。
不要在列上使用函式和進行運算
不要在列上使用函式,這將導致索引失效而進行全表掃描。
- select*from news where year(publish_time)<2017
為了使用索引,防止執行全表掃描,可以進行改造。
- select*from news where publish_time <'2017-01-01'
還有一個建議,不要在列上進行運算,這也將導致索引失效而進行全表掃描。
- select*from news where id /100=1
為了使用索引,防止執行全表掃描,可以進行改造。
- select*from news where id =1*100
儘量避免使用 != 或 not in或 <> 等否定操作符
應該儘量避免在 where 子句中使用 != 或 not in 或 <> 操作符,因為這幾個操作符都會導致索引失效而進行全表掃描。
儘量避免使用 or 來連線條件
應該儘量避免在 where 子句中使用 or 來連線條件,因為這會導致索引失效而進行全表掃描。
- select*from news where id =1or id =2
多個單列索引並不是最佳選擇
MySQL 只能使用一個索引,會從多個索引中選擇一個限制最為嚴格的索引,因此,為多個列建立單列索引,並不能提高 MySQL 的查詢效能。
假設,有兩個單列索引,分別為 news_year_idx(news_year) 和 news_month_idx(news_month)。現在,有一個場景需要針對資訊的年份和月份進行查詢,那麼,SQL 語句可以寫成:
- select*from news where news_year =2017and news_month =1
事實上,MySQL 只能使用一個單列索引。為了提高效能,可以使用複合索引 news_year_month_idx(news_year, news_month) 保證 news_year 和 news_month 兩個列都被索引覆蓋。
複合索引的最左字首原則
複合索引遵守“最左字首”原則,即在查詢條件中使用了複合索引的第一個欄位,索引才會被使用。因此,在複合索引中索引列的順序至關重要。如果不是按照索引的最左列開始查詢,則無法使用索引。
假設,有一個場景只需要針對資訊的月份進行查詢,那麼,SQL 語句可以寫成:
- select*from news where news_month =1
此時,無法使用 news_year_month_idx(news_year, news_month) 索引,因為遵守“最左字首”原則,在查詢條件中沒有使用複合索引的第一個欄位,索引是不會被使用的。
覆蓋索引的好處
如果一個索引包含所有需要的查詢的欄位的值,直接根據索引的查詢結果返回資料,而無需讀表,能夠極大的提高效能。因此,可以定義一個讓索引包含的額外的列,即使這個列對於索引而言是無用的。
範圍查詢對多列查詢的影響
查詢中的某個列有範圍查詢,則其右邊所有列都無法使用索引優化查詢。
舉個例子,假設有一個場景需要查詢本週釋出的資訊文章,其中的條件是必須是啟用狀態,且釋出時間在這周內。那麼,SQL 語句可以寫成:
- select*from news where publish_time >='2017-01-02'and publish_time <='2017-01-08'and enable =1
這種情況下,因為範圍查詢對多列查詢的影響,將導致 news_publish_idx(publish_time, enable) 索引中 publish_time 右邊所有列都無法使用索引優化查詢。換句話說,news_publish_idx(publish_time, enable) 索引等價於 news_publish_idx(publish_time) 。
對於這種情況,我的建議:對於範圍查詢,務必要注意它帶來的副作用,並且儘量少用範圍查詢,可以通過曲線救國的方式滿足業務場景。
例如,上面案例的需求是查詢本週釋出的資訊文章,因此可以建立一個news_weekth 欄位用來儲存資訊文章的周資訊,使得範圍查詢變成普通的查詢,SQL 可以改寫成:
- select*from news where news_weekth =1and enable =1
然而,並不是所有的範圍查詢都可以進行改造,對於必須使用範圍查詢但無法改造的情況,我的建議:不必試圖用 SQL 來解決所有問題,可以使用其他資料儲存技術控制時間軸,例如 Redis 的 SortedSet 有序集合儲存時間,或者通過快取方式快取查詢結果從而提高效能。
索引不會包含有NULL值的列
只要列中包含有 NULL 值都將不會被包含在索引中,複合索引中只要有一列含有 NULL值,那麼這一列對於此複合索引就是無效的。
因此,在資料庫設計時,除非有一個很特別的原因使用 NULL 值,不然儘量不要讓欄位的預設值為 NULL。
隱式轉換的影響
當查詢條件左右兩側型別不匹配的時候會發生隱式轉換,隱式轉換帶來的影響就是可能導致索引失效而進行全表掃描。下面的案例中,date_str 是字串,然而匹配的是整數型別,從而發生隱式轉換。
- select*from news where date_str =201701
因此,要謹記隱式轉換的危害,時刻注意通過同類型進行比較。
like 語句的索引失效問題
like 的方式進行查詢,在 like “value%” 可以使用索引,但是對於 like “%value%” 這樣的方式,執行全表查詢,這在資料量小的表,不存在效能問題,但是對於海量資料,全表掃描是非常可怕的事情。所以,根據業務需求,考慮使用 ElasticSearch 或 Solr 是個不錯的方案。