###### tags: `Index研究` # 重要觀念 ### 不是索引越多越好 索引可以加快查詢速度,但注意它是以空間換取時間。 基本上它使用的資源如下 : 每個索引都會建立一顆 b+ 樹。 每次新增、更新資料時都會改變 b+ 樹。 所以當你索引越多時,你所需要的記憶體與維護索引的 cpu 運算就需要越多。 > mongo的話就是建立B樹 ### 索引不是建了就會使用 在 mysql 的世界,不是建了索引,且下的 query 正常就會一定會使用。 例如有以下的索引 ```sql= table: user field: name, sex index: {sex} ``` 然後執行下面的 sql : ```sql= SELECT * FROM user WHERE sex = 0 ( 0 代表女生 ) ``` 那這時會不會用索引呢 ? 答案是不一定,如果大部份的值都是女生,那 mysql 會用全掃,如果大部份值為男生,那 mysql 會用索引。 > 在mongo資料庫中,索引的欄位佔超過50%以上也會降低索引的效能,所以被索引的欄位需慎選,越分散效能越好。 > 結果集在原集合中所佔的比例越大,查詢效率越慢。因為使用索引需要進行兩次查找:一次查找索引條目,一次根據索引指針去查找相應的文檔。而全表掃描只需要進行一次查詢。在最壞的情況,使用索引進行查找次數會是全表掃描的兩倍。效率會明顯比全表掃描低。 > 而相反在提取較小的子數據集時,索引就非常有效 > ex:查找100筆中的60筆,利用index查需要進行120次查詢(60次找到指針,60次根據指針去找相應文檔),而使用全表查詢只需100次 ### 利用Explain分析索引性能 ![](https://i.imgur.com/T8clkhT.png) # 注意事項 ### 連合索引的欄位順序 假設有一個連合索引如下,由三個欄位 a、b、c 組合而成,而事實上在使用時,可以將它想成有下以三種組合,當然這不代表他有存放三顆樹。 ``` {a, b, c} = {a} {a,b} {a,b,c} ``` 然後根據三序的組合,使用上有個準則。 >tip:有用到最左邊的欄位的才能使用連合索引 以上面連合索引範例為例,下面為使用的 sql 是否會用到索引的情境。 ```sql= SELECT * FROM Table WHERE a = ? ( good 索引 ) SELECT * FROM Table WHERE a = ? AND b = ? ( good 索引 ) SELECT * FROM Table WHERE b = ? AND a = ? ( good 索引 ) SELECT * FROM Table WHERE b = ? ( bad 全掃 ) SELECT * FROM Table WHERE c = ? ( bad 全掃 ) SELECT * FROM Table WHERE b = ? AND c = ? ( bad 全掃 ) ``` ### 儘可能使用索引的排序 首先有個重點要記得,如下圖使用『 年齡 』所建立的索引 : 索引本身就是有排序的 ![](https://i.imgur.com/PYxYPQE.png) 這也代表如果要進行排序,儘可能的直接使用它,而不要讓資料庫另外開空間,來排序它。 **索引欄位: { age }** ```sql= SELECT * FROM user WHERE age <= 30 ORDER BY age; ( good 索引 ) SELECT * FROM user WHERE age <= 30 ORDER BY name; ( bad using filesort ) ``` 其中上述範例中 bad 的 filesort 就是代表 mysql 需要另外使用記憶體來排序,這可以在 explain 時看到。 那連合索引呢 ? 它也有排序。 連合索引是以最左邊的欄位排序 所以假設你有一個索引為 : **{ age, name }** 那它預設就會以 age 來排序,如下圖所示。 ![](https://i.imgur.com/ny0X9Hw.png) {%hackmd theme-dark %}