天天看點

Mongodb Manual閱讀筆記:CH7 索引 7索引

對于頻繁使用查詢,索引提供了高性能。

<a href="#_Toc381385665">7索引... 1</a>

<a href="#_Toc381385666">7.1索引介紹... 2</a>

<a href="#_Toc381385667">7.1.1 索引類型... 3</a>

<a href="#_Toc381385668">7.1.1.1 預設_id. 3</a>

<a href="#_Toc381385669">7.1.1.2 單字段索引(Single Field)3</a>

<a href="#_Toc381385670">7.1.1.3複合索引(Compound Index)3</a>

<a href="#_Toc381385671">7.1.1.4 Multikey Index. 3</a>

<a href="#_Toc381385672">7.1.1.5地理空間索引... 4</a>

<a href="#_Toc381385673">7.1.1.6文本索引... 4</a>

<a href="#_Toc381385674">7.1.1.7 Hash索引... 4</a>

<a href="#_Toc381385675">7.1.2索引屬性... 4</a>

<a href="#_Toc381385676">7.1.2.1唯一索引... 4</a>

<a href="#_Toc381385677">7.1.2.2稀疏索引... 4</a>

<a href="#_Toc381385678">7.2 索引概述... 5</a>

<a href="#_Toc381385679">7.2.1索引類型... 5</a>

<a href="#_Toc381385680">7.2.1.1索引類型特性... 5</a>

<a href="#_Toc381385681">7.2.1.2索引類型文檔... 5</a>

<a href="#_Toc381385682">7.2.2索引屬性... 8</a>

<a href="#_Toc381385683">7.2.2.1 TTL索引... 8</a>

<a href="#_Toc381385684">7.2.2.2唯一索引... 8</a>

<a href="#_Toc381385685">7.2.2.3稀疏索引... 8</a>

<a href="#_Toc381385686">7.2.3建立索引... 9</a>

<a href="#_Toc381385687">7.2.3.1背景建構... 9</a>

<a href="#_Toc381385688">7.2.3.2 删除重複... 9</a>

<a href="#_Toc381385689">7.2.3.3 索引名... 10</a>

<a href="#_Toc381385690">7.3索引教程... 10</a>

<a href="#_Toc381385691">7.3.1建立索引... 10</a>

<a href="#_Toc381385692">7.3.1.1建立一個索引... 10</a>

<a href="#_Toc381385693">7.3.1.2建立複合索引... 10</a>

<a href="#_Toc381385694">7.3.1.3建立唯一索引... 10</a>

<a href="#_Toc381385695">7.3.1.4建立稀疏索引... 11</a>

<a href="#_Toc381385696">7.3.1.5建立hash索引... 11</a>

<a href="#_Toc381385697">7.3.1.6在複制集上建立索引... 11</a>

<a href="#_Toc381385698">7.3.1.7背景建立索引... 11</a>

<a href="#_Toc381385699">7.3.1.8建立老式索引... 12</a>

<a href="#_Toc381385700">7.3.2索引管理教程... 12</a>

<a href="#_Toc381385701">7.3.2.1删除所有... 12</a>

<a href="#_Toc381385702">7.3.2.2重建索引... 12</a>

<a href="#_Toc381385703">7.3.2.3管理在建索引... 12</a>

<a href="#_Toc381385704">7.3.2.4傳回所有索引... 12</a>

<a href="#_Toc381385705">7.3.2.5評估索引的使用... 13</a>

<a href="#_Toc381385706">7.3.3地理空間索引教程... 13</a>

<a href="#_Toc381385707">7.3.4文本查詢教程... 13</a>

<a href="#_Toc381385708">7.3.4.1啟動文本查詢... 13</a>

<a href="#_Toc381385709">7.3.4.2建立文本索引... 13</a>

<a href="#_Toc381385710">7.3.4.3查詢文本... 14</a>

<a href="#_Toc381385711">7.3.4.4指定語言... 15</a>

<a href="#_Toc381385712">7.3.4.5為文本索引建立名字... 16</a>

<a href="#_Toc381385713">7.3.4.6使用權重控制查詢... 17</a>

<a href="#_Toc381385714">7.3.4.7限制掃描行數... 17</a>

<a href="#_Toc381385715">7.3.4.8建立文本覆寫索引... 18</a>

<a href="#_Toc381385716">7.3.5索引政策... 18</a>

<a href="#_Toc381385717">7.3.5.1建立索引支援查詢... 18</a>

<a href="#_Toc381385718">7.3.5.2為排序的查詢提供順序... 19</a>

<a href="#_Toc381385719">7.3.5.3保證索引都在記憶體中... 19</a>

<a href="#_Toc381385720">7.3.5.4保證查詢的選擇性... 19</a>

<a href="#_Toc381385721">7.4索引指南... 19</a>

索引是查詢高效的解決方案。如果沒有索引,那麼mongodb會掃描整個collection。索引是一個b樹結構,儲存了collection中的部分資料。

當查詢可以使用某個索引的時候,mongodb會使用索引來限制輸入文檔的個數。如:

Mongodb Manual閱讀筆記:CH7 索引 7索引

建立了索引,隻保證少部分的資料被掃描。

對于排序,如果有索引可用,可以不需要排序後在輸出。索引本來就是有順序的。

對于覆寫,當查詢的标準和projection都在這個索引裡面,查詢會直接從索引中傳回,不會掃描collection。

Mongodb提供了不同的索引類型來支援資料查詢。

如果應用程式沒有給_id指定特别的值,mongod會自動在_id 上建立索引。

_id是一個唯一索引,當相同的_id 被插入就會報錯

在一個字段為key建立的索引叫做單字段索引。

Mongodb Manual閱讀筆記:CH7 索引 7索引

如果在多個字段為key那麼就是複合索引,如:

Mongodb Manual閱讀筆記:CH7 索引 7索引

如果一個字段是一個數組,在這個字段上面建立索引。Mongodb會自己決定,是否要把這個索引建成Multikey Index。

Mongodb Manual閱讀筆記:CH7 索引 7索引

Mongodb提供了2個地理索引,2d index,2sphere Index。

文本索引不儲存指定的stop word和stem word隻保留詞根。

Hash索引時對key進行hash計算然後建立索引,目前隻支援等号運作,不支援區間。

索引的唯一屬性,會拒絕key的重複值插入

稀疏屬性保證了索引隻包含有字段值的(對于mongo來說null也是一個值)

本節介紹mongo中types,配置選項和索引的特性。

MongoDB提供了很多不同的索引類型

所有索引在Mongodb中都是B樹結構,可以有效的支援相等的比對和區間查詢,也可以以索引順序直接輸出

MongoDB索引有順序和逆序2中排序方式,對于單字段索引而言,順序和逆序是沒什麼差別的。對于複合索引而言,有時候順序轉化是不行的。

一個查詢隻能使用一個索引,但是對于or,每個子句都可以使用其他的索引

本節介紹索引,單字段索引,複合索引,Multikey Indexes,地理空間索引,文本索引,Hash索引

Mongodb預設所有的collection都有個單字段索引,_id。

如果有一個friends collection,:

{ "_id" : ObjectID(...),

"name" : "Alice"

"age" : 27

}

可以使用一下語句在name上建立索引:

db.friends.ensureIndex( { "name" : 1 } )

案例

_id索引:_id上的索引是預設建立的,并且不能删除而且是唯一的。如果不顯示的插入值,_id為ObjectID類型長度為12位元組。

在子文檔字段上的索引:你可以在一個子文檔上建立索引,如:

{"_id": ObjectId(...)

"name": "John Doe"

"address": {

"street": "Main"

"zipcode": 53511

"state": "WI"

然後再address上建立索引:

db.people.ensureIndex( { "address.zipcode": 1 } )

在子文檔上建立索引:同時也可以對整個子文檔建立索引:

{

_id: ObjectId("523cba3c73a8049bcdbf6007"),

metro: {

city: "New York",

state: "NY"

},

name: "Giant Factory"

db.factories.ensureIndex( { metro: 1 } )

db.factories.find( { metro: { city: "New York", state: "NY" } } )

比對成功然後傳回上面的文檔,但是一下的查詢就比對不了:

db.factories.find( { metro: { state: "NY", city: "New York" } } )

當key字段大于1個的時候都被叫做複合索引。

建立方法:

db.products.ensureIndex( { "item": 1, "stock": 1 } )

對已經hash索引的字段不能建立複合索引。并且複合索引字段個數最多31個

複合索引的排序,是先對第一個字段排序,然後第二個依次類推。

查詢可以使用複合索引裡面的字首,都可以使用到這個索引。

排序順序

複合索引的本身的排序順序會影響查詢是否可以使用索引的順序。

如索引:db.events.ensureIndex( { "username" : 1, "date" : -1 } )

db.events.find().sort( { username: 1, date: -1 } )

db.events.find().sort( { username: -1, date: 1 } )

都可以使用這個索引的順序,但是一下查詢使用不了:

db.events.find().sort( { username: 1, date: 1 } )

Multikey索引允許MongoDB傳回在數組上的查詢。Mongodb自己決定是否對數組建立multikey index。

Multikey支援數組值和嵌套文檔

限制

複合索引和Multikey索引的互相作用:當你建立複合索引的multikey,隻能有一個字段是數組,如果建立了複合索引,在2個字段上都已經是數組,那麼插入就會回絕。

Hash索引:hase索引不能被multikey索引相容。MongoDB會折疊子文檔,然後計算整個的hash值。

在嵌入文檔數組中的索引:你可以使用在子文檔數組上建立multikey索引。

手冊p326

文本索引是區分大小寫的,并且可以是字元串,和字元串數組。

要使用text索引,和使用text指令要先啟用text搜尋。

建立文本索引:建立文本索引,如:

db.reviews.ensureIndex( { comments: "text" } )

文本索引或删除stop word和字尾。文本索引可以覆寫查詢。

存儲需求和性能花費:有以下幾個花費和需求:

1.       文本索引修改了collection中的空間配置設定的方法為usePowerOf2Sizes

2.       文本索引比較大。為每個單詞建立一個索引項

3.       建立文本索引和建立multikey索引很類似,會花費大量的時間

5.       文本索引會影響插入的吞吐量,要為每一個單詞索引

6.       另外,文本索引不儲存短語或者資訊中近似的單詞

文本查詢:mongodb提供了text指令來執行文本搜尋。搜尋過程如下:

         1.在索引建立和text指令執行的時候先标記和提取查詢的term

         2.為比對到的文檔配置設定一個分數,分數決定的文檔和關鍵字之間的關聯

預設text指令傳回前100關聯比較強的文檔。

Hash索引維護了索引字段的hash值,如果是子文檔,那麼會對真個子文檔做hash計算。Hash索引支援shard collection作為shard key。

Mongodb可以在相等比對的時候使用hash索引,區間比對的時候不能使用。

如果已經在這個字段上建立了hash索引,那麼不能再在上面建立複合索引,但是可以建立單字段索引。

Mongodb除了支援多種索引之外,還支援不同的索引屬性。

建立了TTL索引,Mongodb會根據TTL索引自動删除collection的文檔。比較适用于事件資料,日志,回話資訊。

這個索引有一下幾個限制:

         1.不支援複合索引

         2.索引字段必須是時間類型

         3.如果是一個數組,當數組内的時間任意一個過期,就算過期

唯一索引會回絕所有重複的鍵值。

db.addresses.ensureIndex( { "user_id": 1 }, { unique: true } )

如果在複合索引上建立唯一,那麼複合索引裡面的key的組合是唯一的,而不是單個key唯一。

文檔插入,如果沒有key,那麼會被當null存,如果有一個唯一索引在這個字段上,又插入一個沒有key的文檔,那麼就會報錯。你可以再加稀疏索引來過濾這些空值。

稀疏索引隻包含了有這個字段的文檔,即便這個字段是null值,當文檔沒有這個值的時候,就不會被儲存到稀疏索引中。如:

{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }

{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }

{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }

db.scores.ensureIndex( { score: 1 } , { sparse: true } )

db.scores.find().sort( { score: -1 } )

查詢隻會傳回有score的文檔。

稀疏索引和唯一索引:稀疏索引和唯一索引一起使用可以達到,關系型資料庫中建的效果(不能為空,不能重複)。

Mongodb建立索引通過db.collection.ensureIndex()方法,

預設建立索引都會把其他資料庫操作block,對于一個運作比較長的索引建立,可以考慮背景運作。

db.people.ensureIndex( { zipcode: 1}, {background: true} )

背景建立預設為false。

在2.4版本之後,mongod可以支援多個索引在背景同時建立。

背景建立之後資料庫還可以正常運作,不會被堵塞,但是目前建立索引的回話會被堵塞,直到建立完成。如果背景建立了索引,那麼就不能執行其他的管理操作。

背景索引建立是使用遞增的方式,比通常的(前台)索引建立要慢,如果索引比記憶體大,那麼會更加大的慢。

為了避免出現性能問題,最好在資料庫設計階段就确定好索引的索引設計。

在primary使用背景索引建立,到了secondary之後會變成前台建立。所有的索引操作在secondary中都會被block。

在secondary中建立大索引最好的方式是,重新開機secondary到standalone狀态,然後建立索引,建立完之後再加入到複制集,然後趕上primary之間的滞後。然後在下一個secondary上建立。當所有的secondary建好之後,切換primary,然後重新開機變為standalone,建立索引。

當在secondary上建立索引的時候,oplog需要有足夠的空間。

當collection中有重複鍵,那麼就無法建立唯一索引,可以使用dropDups選項強制删除索引,會報存第一個key,接下來的重複的key的文檔都會被删除。

如:

db.accounts.ensureIndex( { username: 1 }, { unique: true, dropDups: true } )

預設這個選項為false

預設索引名和key,排序順序有關,如:db.products.ensureIndex( { item: 1, quantity: -1 } )的索引名為:item_1_quantity_-1,可以使用以下來修改指定索引名:

db.products.ensureIndex( { item: 1, quantity: -1 } , { name: "inventory" } )

本節介紹,索引建立,索引管理,地理空間索引,文本搜尋,索引政策

Mongodb預設會在_id上建立一個索引,并允許使用者在任意字段上建立索引

可以使用ensureIndex()在單個字段上建立索引。

如:db.people.ensureIndex( { "phone-number": 1 } )

額外考慮:如果collection太大,可以考慮背景建立,讓資料庫處于可用狀态,不會被堵塞。

複合索引好處,是提供了索引覆寫,可以直接從索引中傳回資料。

建立複合索引:db.collection.ensureIndex( { a: 1, b: 1, c: 1 } )

唯一索引隻是索引的一個屬性

db.collection.ensureIndex( { a: 1 }, { unique: true } )

一般唯一索引和稀疏索引一起使用:db.collection.ensureIndex( { a: 1 }, { unique: true, sparse: true } )

也可以在複合索引上建立唯一屬性。

删除重複:可以删除重複的key

db.collection.ensureIndex( { a: 1 }, { unique: true, dropDups: true } )

稀疏索引和非稀疏索引不同,非稀疏索引會包含所有的文檔,如果沒有這個字段用null填充,稀疏索引如果文檔沒有這個字段,那麼就不會為這個文檔index。

db.collection.ensureIndex( { a: 1 }, { sparse: true } )

Hash索引時對索引字段進行hash計算,隻能使用者等号的比對,不能用于區間比對。

db.collection.ensureIndex( { _id: "hashed" } )

考慮:hash索引可以在任何字段上建立,包括子文檔,會把所有的的内容計算hash,不支援multikey。

背景建立索引在secondary會變成前台,前台建立索引會把複制block,secondary會在primary建立了索引之後再建立,如果在shard中有複制集,那麼會現在shard的primary上建立,然後再secondary上建立。

需要保證oplog有足夠的空間,用來儲存延遲。

1.關閉一個Secondary:先關閉一個secondary然後以啟動不加—replSet選項,使用不同的端口運作。

2.建立索引:使用ensure建立索引

3.重新開機mongod:建立完之後重新開機mongod加上選項—replSet修改到原來的端口。

4.在所有secondary上建立索引:每個secondary根據以上1-3步建立索引

5.在primary上建立索引二選一:

         a.先在primary在上是有背景建立索引

         b.然後關閉primary,讓别的secondary變成primary,在通過1-3步建立索引。

在背景建立索引,會比前台建立索引時間長,并且緊湊性比較差,并且會影響primary寫入性能。

前台索引建立會block資料,背景索引建立可以讓資料庫任然可用,在背景索引建立時,資料庫申請讀寫鎖不會被擷取。

db.collection.ensureIndex( { a: 1 }, { background: true } )

手冊page346

本節介紹對索引的管理:删除所有,重建索引,管理在建立的索引,傳回所有索引,評估索引的使用

可以使用dropIndex()方法來删除索引,db.accounts.dropIndex( { "tax-id": 1 } )

傳回{ "nIndexesWas" : 3, "ok" : 1 }

nindexesWas表示删除之前的索引個數,

可以使用db.collection.dropIndex()來删除collection下的所有索引。

使用db.collection.reIndex()方法來重建collection下的所有索引。

可以使用db.curentOp(),msg字段會指明是否在建立索引,進度。如果不想再建立可以使用db.killop來停止建立。

索引的中繼資料存放在system.indexex下面

db.people.getIndexes()

db.system.indexes.find()

查詢性能能夠很好的指明索引的使用

使用explain傳回執行計劃:在cursor下有個explain檢視查詢執行計劃,其中包含了使用的索引。

使用hint:使用hint來強制使用索引

db.people.find( { name: "John Doe", zipcode: { $gt: 63000 } } } ).hint( { zipcode: 1 } )

使用報表:

serverStatus的輸出indexCounters,scanned,scanAndOrder

collStats的輸出totalIndexSize,indexSizes

dbStats的輸出dbStats.indexes,bStats.indexSize

手冊p349

本節介紹,啟動文本查詢,建立文本索引,查詢文本,指定語言,為文本索引建立名稱,使用權重控制查詢結果,限制沒掃描的文檔,建立覆寫索引

文本查詢現在還是beta版本,一下特性:

1.需要先啟動文本查詢

2.如果要為shard或者複制集啟動文本查詢,要在每個mongod中都啟動

mongod --setParameter textSearchEnabled=true

也可以在配置檔案中設定textSearchEnable。

可以在多個包含字元串或者字元串數組上面建立文本索引

db.collection.ensureIndex(

subject: "text",

content: "text"

})

為所有是字元串的字段建立索引可以使用,通配符($**)

{ "$**": "text" },

{ name: "TextIndex" }

                                     )

db.quotes.runCommand( "text", { search: "TOMORROW" } )

文本是大小寫敏感的,使用text指令查詢。

db.quotes.runCommand( "text", { search: "tomorrow largo" } )

查詢包含tomorrow或者largo的文檔

db.quotes.runCommand( "text", { search: "\"and tomorrow\"" } )

這個可以用來比對and tomorrow短語

查詢的時候有短語和獨立的組時,短語群組之間使用and,組群組之間使用or

類似于(corto OR largo OR tomorrow) AND ("and tomorrow")

Tomorrow來至于短語。

db.quotes.runCommand( "text" , { search: "tomorrow -petty" } )

比對tomorrow,但是不包含petty

預設text指令會傳回100個文檔,可以使用limit來限制傳回

db.quotes.runCommand( "text", { search: "tomorrow", limit: 2 } )

Text指令中可以使用project來控制傳回的列,1傳回,0不傳回

db.quotes.runCommand( "text", { search: "tomorrow",

project: { "src": 1 } } )

Text指令的filter選項提供了這個功能。之間是and關系

filter: { speaker : "macbeth" } } )

語言決定了stop word和stem word

db.quotes.runCommand( "text", { search: "amor", language: "spanish" } )

文本查詢的結果以文檔的方式輸出

如果不填預設語言,語言為英語。如果要指定不同的語言可以在建立索引的時候指定。

{ content : "text" },

{ default_language: "spanish" }

)

在文檔中指定語言:

         1.如果文檔儲存一個language的字段,預設建立索引的時候會以這個字段為語言,來覆寫預設的英文

         2.如果語言字段沒有language字段,而是别的字段,那麼在索引建立的時候,使用language_override指向這個字段。

包含language字段:

         { _id: 1, language: "portuguese", quote: "A sorte protege os audazes" }

{ _id: 2, language: "spanish", quote: "Nada hay más surreal que la realidad." }

{ _id: 3, language: "english", quote: "is this a dagger which I see before me" }

         db.quotes.ensureIndex( { quote: "text" } )

         如果文檔裡面有language,建立索引使用這個語言

         如果沒有,則使用英文。

db.quotes.runCommand( "text", { search: "que", language: "spanish" } )

因為在西班牙語上面que是stop word 是以比對不到任何東西。

指定一個字段作為語言:

         可以使用language_override選項上指定字段作為語言

         { _id: 1, idioma: "portuguese", quote: "A sorte protege os audazes" }

{ _id: 2, idioma: "spanish", quote: "Nada hay más surreal que la realidad." }

{ _id: 3, idioma: "english", quote: "is this a dagger which I see before me" }

db.quotes.ensureIndex( { quote : "text" },

{ language_override: "idioma" } )

         1.如果包含idioma字段,那麼以這個字段裡面的語言作為語言

         2.如果沒有用英語

預設文本索引建立好後,mongo會自動為這個索引建立一個名字

content: "text",

"users.comments": "text",

"users.profiles": "text"

"content_text_users.comments_text_users.profiles_text"

當然也可以指定索引名

{content: "text",

{name: "MyTextIndex"}

預設text指令根據分數(scores)從高到低來比對文檔。對于文本索引來說,權重就表示這個字段和其他字段對于查詢組來說的重要性。

預設所有的索引字段的權重都是1,可以在建立索引的時候調整

db.blog.ensureIndex(

keywords: "text",

about: "text"

weights: {

content: 10,

keywords: 5,

name: "TextIndex"

就是用索引來現在掃描行數

{ _id: 1, dept: "tech", description: "a fun green computer" }

{ _id: 2, dept: "tech", description: "a wireless red mouse" }

{ _id: 3, dept: "kitchen", description: "a green placemat" }

{ _id: 4, dept: "kitchen", description: "a red peeler" }

{ _id: 5, dept: "food", description: "a green apple" }

{ _id: 6, dept: "food", description: "a red potato" }

db.inventory.runCommand( "text", {

earch: "green",

filter: { dept : "kitchen" }

db.inventory.ensureIndex({

dept: 1,

description: "text"

因為會掃描過濾特定的字段kitchen,然後建立一個符合索引把dept放在前面。

1.排序索引必須在文本索引的前面

2.隻會對符合prefix的進行索引

3.不能再有multikey索引或者地理空間索引

4.text指令必須要辦filter,并且使用等号條件。

這樣的話指定的dept會限制掃描的行數

1.添加text到排序索引中

2.使用text指令的時候使用project限制字段。

db.collection.ensureIndex( { comments: "text",username: 1 } )

db.quotes.runCommand( "text", { search: "tomorrow",project: { username: 1,_id: 0}})

當設計索引的時候,要考慮讀寫的比例,記憶體,查詢的類型。

在建立索引的時候,要知道所有的查詢,雖然索引有性能的消耗,但是對查詢的效果是很明顯的。

要驗證索引是否還有用,哪些運作的最好,如果這個索引沒用了,那麼請幹掉。

當所有覆寫的時候mongo擷取掃描索引,而不是從collection中要資料。

如果你的索引隻對一個key進行查詢那麼建立一個單字段索引。

複合索引有多個key組成,主要複合prefix,都可以使用到複合索引。

覆寫索引是為了讓mongo不再去掃描collection中的資料

1.所有的查詢中的字段都要在索引中

2.所有結果傳回的字段也要在索引中

這樣效率比較高,因為索引要不再記憶體中,要不就是在磁盤中但是是順序的。

使用explain()中的indexOnly如果為true那麼就是覆寫的,否則就不是

可以使用索引裡面的排序,為查詢提供了很好的性能。

如果索引時一個覆寫索引,并且查詢時索引的prefix,并且前面是使用相等的比對,那麼就可以使用索引的排序。或者排序時覆寫索引的prefix,也可以使用索引的排序。

explain()傳回中如果scanAndOrder為false說明可以使用索引順序

使用db.collection.totalIndexSize()函數檢視索引大小,保證加上workset之後比實體記憶體小。如果有多個collection,那麼要看所有的索引大小和workset都可以同時在記憶體中。

有些索引時不需要全部都在記憶體中的,隻要保證最常用的在記憶體中的就可以了。

選擇性是使用索引限制傳回行數的能力,低選擇性的索引對查詢本身就沒有什麼很大的好處。可以讓多個低選擇性的字段組合成複合索引,來提高選擇性,或者低選擇性的字段和高選擇性的字段組合成複合索引。

低選擇性可能比查詢整個collection還要慢。

手冊p374