MongoDB の豊富なインデックス タイプについて話しましょう

青灯夜游
リリース: 2022-02-17 10:59:16
転載
2718 人が閲覧しました

この記事では、MongoDB を理解し、MongoDB の豊富なインデックス タイプを紹介します。皆様のお役に立てれば幸いです。

MongoDB の豊富なインデックス タイプについて話しましょう

MongoDB のインデックスと MySql のインデックスの機能は、機能と最適化原則の点で基本的に似ています。 MySqlインデックス タイプは基本的に次のように区別できます。

  • 単一キー インデックス - ジョイント インデックス
  • 主キー インデックス (クラスター化インデックス) - 非主キー インデックス (非クラスター化インデックス)

MongoDB には、これらの基本的な分類に加えて、配列インデックス | スパース インデックス | 地理空間インデックス | TTL インデックスなどの特殊なインデックス タイプもあります。 etc.

以下のテストの便宜上、スクリプトを使用して次のデータを挿入します

for(var i = 0;i < 100000;i++){
    db.users.insertOne({
        username: "user"+i,
        age: Math.random() * 100,
        sex: i % 2,
        phone: 18468150001+i
    });
}
ログイン後にコピー

単一キー インデックス

単一キー インデックスの意味最も基本的なインデックスであるインデックス付きフィールドが 1 つだけであることを示します。Method.

コレクション内の

username フィールドを使用して、単一のキー インデックスを作成します。MongoDBこのインデックスには自動的に username_1

db.users.createIndex({username:1})
&#39;username_1&#39;
ログイン後にコピー

という名前が付けられます。インデックスを作成した後、

username フィールドを使用してクエリ プランを確認します。stage IXSCAN (インデックス スキャンが使用されることを意味します)

db.users.find({username:"user40001"}).explain()
{ 
   queryPlanner: 
   { 
     winningPlan: 
     { 
        ......
        stage: &#39;FETCH&#39;,
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { username: 1 },
           indexName: &#39;username_1&#39;,
           ......
        } 
     }
     rejectedPlans: [] ,
   },
   ......
   ok: 1 
}
ログイン後にコピー

インデックス最適化の原則の中で、非常に重要な原則は、インデックスはカーディナリティの高いフィールド上に構築されるべきであるということです。いわゆるカーディナリティは次のとおりです。フィールド内の非反復値の数、つまり

users を作成するとき。収集中に表示される年齢の値が 0-99 の場合、 age フィールドには 100 個の一意の値が含まれます。つまり、age フィールドのベースは 100 です。 sex フィールドには 2 つの値のみが含まれます 0 | 1、つまり、sex フィールドの基数は 2 であり、かなり低い基数です。この場合、インデックスの効率は高くなく、インデックスの失敗につながります。 # 実行プランをクエリするための

sex

フィールド インデックスを構築しましょう。クエリが関連インデックスなしでフル テーブル スキャンを実行したことがわかります。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">db.users.createIndex({sex:1}) &amp;#39;sex_1&amp;#39; db.users.find({sex:1}).explain() { queryPlanner: { ...... winningPlan: { stage: &amp;#39;COLLSCAN&amp;#39;, filter: { sex: { &amp;#39;$eq&amp;#39;: 1 } }, direction: &amp;#39;forward&amp;#39; }, rejectedPlans: [] }, ...... ok: 1 }</pre><div class="contentsignin">ログイン後にコピー</div></div>

ジョイント インデックス

結合インデックスは、インデックスに複数のフィールドが存在することを意味します。以下の

age## を使用します。# と

sex は、2 つのフィールド

db.users.createIndex({age:1,sex:1})
&#39;age_1_sex_1&#39;
ログイン後にコピー
## を持つインデックスを作成します# 次に、これら 2 つのフィールドを使用してクエリを実行し、実行計画を確認し、このインデックスを正常に実行します <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">db.users.find({age:23,sex:1}).explain() { queryPlanner: { ...... winningPlan: { stage: &amp;#39;FETCH&amp;#39;, inputStage: { stage: &amp;#39;IXSCAN&amp;#39;, keyPattern: { age: 1, sex: 1 }, indexName: &amp;#39;age_1_sex_1&amp;#39;, ....... indexBounds: { age: [ &amp;#39;[23, 23]&amp;#39; ], sex: [ &amp;#39;[1, 1]&amp;#39; ] } } }, rejectedPlans: [], }, ...... ok: 1 }</pre><div class="contentsignin">ログイン後にコピー</div></div>

配列インデックス

配列インデックスは、配列フィールドのインデックス (複数値インデックスとも呼ばれます)。テストするために、users コレクション内のデータが以下のいくつかの配列フィールドに追加されます。

db.users.updateOne({username:"user1"},{$set:{hobby:["唱歌","篮球","rap"]}})
......
ログイン後にコピー

配列を作成するインデックスを作成し、その実行プランを表示します。isMultiKey: true は、使用されるインデックスが複数値のインデックスであることを意味します。

db.users.createIndex({hobby:1})
&#39;hobby_1&#39;

db.users.find({hobby:{$elemMatch:{$eq:"钓鱼"}}}).explain()
{ 
   queryPlanner: 
   { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        filter: { hobby: { &#39;$elemMatch&#39;: { &#39;$eq&#39;: &#39;钓鱼&#39; } } },
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { hobby: 1 },
           indexName: &#39;hobby_1&#39;,
           isMultiKey: true,
           multiKeyPaths: { hobby: [ &#39;hobby&#39; ] },
           ......
           indexBounds: { hobby: [ &#39;["钓鱼", "钓鱼"]&#39; ] } } 
         },
     rejectedPlans: [] 
  },
  ......
  ok: 1 
}
ログイン後にコピー

配列インデックスは他のインデックスと比較されます。一般的に、インデックス エントリは、たとえば、各ドキュメントの hobby 配列の平均

size

が 10 である場合、このコレクションの hobby 配列インデックスは次のようになります。 結合配列インデックス

結合配列インデックスとは、配列フィールドを含む結合インデックスです。は 1 つのインデックスをサポートしません。複数の配列フィールドが含まれます。つまり、インデックス内に存在できる配列フィールドは最大 1 つです。これは、インデックス エントリの爆発的な増加を避けるためです。インデックス内に 2 つの配列フィールドがあると仮定すると、その数はインデックス エントリの数は、通常のインデックスの n* になります。m 倍

地理空間インデックス

元の users コレクションに地理情報を追加します。

for(var i = 0;i < 100000;i++){
    db.users.updateOne(
    {username:"user"+i},
    {
        $set:{
            location:{
                type: "Point",
                coordinates: [100+Math.random() * 4,40+Math.random() * 3]
            }
        }
    });
}
ログイン後にコピー

2 番目の次元空間インデックスの作成 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">db.users.createIndex({location:&quot;2dsphere&quot;}) &amp;#39;location_2dsphere&amp;#39; //查询500米内的人 db.users.find({ location:{ $near:{ $geometry:{type:&quot;Point&quot;,coordinates:[102,41.5]}, $maxDistance:500 } } })</pre><div class="contentsignin">ログイン後にコピー</div></div>地理空間インデックスの

type

には、

Ponit(point)

| を含むものが多数あります。 LineString(line) | Polygon (Polygon)etcTTL インデックス

TTL の完全なスペルは、time to です。 live は、主に期限切れデータの自動削除に使用されます。この種のインデックスを使用するには、ドキュメント内で時間型フィールドを宣言する必要があります。また、このフィールドの TTL インデックスを作成するときに、次のことも行う必要があります。

expireAfterSecondsを設定します

作成完了後の有効期限の単位は秒ですMongoDBコレクション内のデータは定期的にチェックされます。表示されるタイミング:<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics>##現在時刻<mrow><mtext>−</mtext><mo>T</mo><mi>T</mi> <mi>L</mi><mi>インデックス フィールド時間</mi><mtext>></mtext><mo>e</mo><mi>xx</mi><mi>p</mi><mi>i</mi> <mi>r</mi><mi>e</mi><mi>A</mi><mi>f</mi><mi>t</mi><mi>e</mi><mi>r</mi><mi>S</mi><mi>r</mi><mi>c</mi><mi>o</mi><mi>n</mi><mi>d</mi><mi>s</mi><mi></mi>現在時刻 - TTL インデックス フィールド時間>expireAfterSrconds</mrow><annotation encoding="application/x-tex"></annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base">##when<span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span>before<span class="mord cjk_fallback"></span> <span class="mord cjk_fallback"></span>间<span class="mord cjk_fallback"></span><span class="mord cjk_fallback"></span>−<span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span>##T<span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;">T</span> <span class="mord mathnormal" style="margin-right:0.13889em;">#L</span><span class="mord mathnormal" style="margin-right:0.13889em;">index</span><span class="mord mathnormal">cite</span><span class="mord cjk_fallback">字</span><span class="mord cjk_fallback">セクション</span><span class="mord cjk_fallback">時間</span><span class="mord cjk_fallback">インター</span><span class="mord cjk_fallback"></span>#><span class="mord cjk_fallback"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"></span><span class="mspace" style="margin-right:0.2777777777777778em;">e</span>##x</span><span class="base">p<span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span>i<span class="mord mathnormal"></span>r<span class="mord mathnormal"></span>e<span class="mord mathnormal"></span>A<span class="mord mathnormal"></span>f<span class="mord mathnormal" style="margin-right:0.02778em;"></span>t<span class="mord mathnormal"></span>e<span class="mord mathnormal"> </span>r<span class="mord mathnormal" style="margin-right:0.10764em;"></span>S<span class="mord mathnormal"></span>r<span class="mord mathnormal"></span>c<span class="mord mathnormal" style="margin-right:0.02778em;"></span>o<span class="mord mathnormal" style="margin-right:0.05764em;"></span>n<span class="mord mathnormal" style="margin-right:0.02778em;"></span>d<span class="mord mathnormal"></span> s<span class="mord mathnormal"></span><span class="mord mathnormal"></span><span class="mord mathnormal"></span><p><code>MongoDB将会自动将这些文档删除,这种索引还有以下这些要求:

  • TTL索引只能有一个字段,没有联合TTL索引
  • TTL不能用于固定集合
  • TTL索引是逐个遍历后,发现满足删除条件会使用delete函数删除,效率并不高

首先在我们文档上增减一个时间字段

for(var i = 90000;i < 100000;i++){
    db.users.updateOne(
    {username:"user"+i},
    {
        $set:{
            createdDate:new Date()
        }
    });
}
ログイン後にコピー

创建一个TTL索引并且设定过期时间为60s,待过60s后查询,会发现这些数据已经不存在

db.users.createIndex({createdDate:1},{expireAfterSeconds:60})
&#39;createdDate_1&#39;
ログイン後にコピー

另外还可以用CollMod命令更改TTL索引的过期时间

db.runCommand({
  collMod:"users",
  index:{
    keyPattern:{createdDate:1},
    expireAfterSeconds:120
  }
})

{ expireAfterSeconds_old: 60, expireAfterSeconds_new: 120, ok: 1 }
ログイン後にコピー

条件索引

条件索引也叫部分索引(partial),只对满足条件的数据进行建立索引.

只对50岁以上的user进行建立username_1索引,查看执行计划会发现isPartial这个字段会变成true

db.users.createIndex({username:1},{partialFilterExpression:{
    age:{$gt:50}
  }})
&#39;username_1&#39;

db.users.find({$and:[{username:"user4"},{age:60}]}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        filter: { age: { &#39;$eq&#39;: 60 } },
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { username: 1 },
           indexName: &#39;username_1&#39;,
           ......
           isPartial: true,
           ......
         } 
     },
     rejectedPlans: [] 
  },
  ......
  ok: 1 
}
ログイン後にコピー

稀疏索引

一般的索引会根据某个字段为整个集合创建一个索引,即使某个文档不存这个字段,那么这个索引会把这个文档的这个字段当作null建立在索引当中.

稀疏索引不会对文档中不存在的字段建立索引,如果这个字段存在但是为null时,则会创建索引.

下面给users集合中的部分数据创建稀疏索引

for(var i = 5000;i < 10000;i++){
  if(i < 9000){
    db.users.updateOne(
      {username:"user"+i},
      { $set:{email:(120000000+i)+"@qq.email"}}
    )
  }else{
    db.users.updateOne(
      {username:"user"+i},
      { $set:{email:null}}
    )
  }
}
ログイン後にコピー

当不建立索引使用{email:null}条件进行查询时,我们会发现查出来的文档包含没有email字段的文档

db.users.find({email:null})
{ 
  _id: ObjectId("61bdc01ba59136670f6536fd"),
  username: &#39;user0&#39;,
  age: 64.41483801726282,
  sex: 0,
  phone: 18468150001,
  location: 
  { 
    type: &#39;Point&#39;,
    coordinates: [ 101.42490900320335, 42.2576650823515 ] 
  } 
}
......
ログイン後にコピー

然后对email这个字段创建一个稀疏索引使用{email:null}条件进行查询,则发现查询来的文档全部是email字段存在且为null的文档.

db.users.createIndex({email:1},{sparse:true});
&#39;email_1&#39;

db.users.find({email:null}).hint({email:1})
{ 
  _id: ObjectId("61bdc12ca59136670f655a25"),
  username: &#39;user9000&#39;,
  age: 94.18397576757012,
  sex: 0,
  phone: 18468159001,
  hobby: [ &#39;钓鱼&#39;, &#39;乒乓球&#39; ],
  location: 
  { 
    type: &#39;Point&#39;,
    coordinates: [ 101.25903151863596, 41.38450145025062 ] 
  },
  email: null 
}
......
ログイン後にコピー

文本索引

文本索引将建立索引的文档字段先进行分词再进行检索,但是目前还不支持中文分词.

下面增加两个文本字段,创建一个联合文本索引

db.blog.insertMany([
  {title:"hello world",content:"mongodb is the best database"},
  {title:"index",content:"efficient data structure"}
])

//创建索引
db.blog.createIndex({title:"text",content:"text"})
&#39;title_text_content_text&#39;
//使用文本索引查询
db.blog.find({$text:{$search:"hello data"}})
{ 
  _id: ObjectId("61c092268c4037d17827d977"),
  title: &#39;index&#39;,
  content: &#39;efficient data structure&#39; 
},
{ 
  _id: ObjectId("61c092268c4037d17827d976"),
  title: &#39;hello world&#39;,
  content: &#39;mongodb is the best database&#39; 
}
ログイン後にコピー

唯一索引

唯一索引就是在建立索引地字段上不能出现重复元素,除了单字段唯一索引还有联合唯一索引以及数组唯一索引(即数组之间不能有元素交集 )

//对title字段创建唯一索引
db.blog.createIndex({title:1},{unique:true})
&#39;title_1&#39;
//插入一个已经存在的title值
db.blog.insertOne({title:"hello world",content:"mongodb is the best database"})
MongoServerError: E11000 duplicate key error collection: mock.blog index: title_1 dup key: { : "hello world" }
//查看一下执行计划,isUnique为true
db.blog.find({"title":"index"}).explain()
{ 
  queryPlanner: 
  { 
     ......
     winningPlan: 
     { 
        stage: &#39;FETCH&#39;,
        inputStage: 
        { 
           stage: &#39;IXSCAN&#39;,
           keyPattern: { title: 1 },
           indexName: &#39;title_1&#39;,
           isMultiKey: false,
           multiKeyPaths: { title: [] },
           isUnique: true,
           ......
         } 
     },
     rejectedPlans: [] 
  },
  .......
  ok: 1 
}
ログイン後にコピー

相关视频教程推荐:《MongoDB教程

以上がMongoDB の豊富なインデックス タイプについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート