---
# System prepended metadata

title: 重要觀念
tags: [Index研究]

---

###### 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 %}