>백엔드 개발 >PHP 튜토리얼 >MongoDB 인덱스를 사용하는 방법

MongoDB 인덱스를 사용하는 방법

小云云
小云云원래의
2017-12-01 11:38:252663검색

이 글에서는 MongoDB 인덱스의 사용법에 대해 자세히 설명하겠습니다. 인덱스는 책의 목차와 같습니다. 목차의 도움 없이 특정 콘텐츠를 검색하면 전체 기사를 검색하고 찾아보기 때문에 효율성이 매우 낮습니다. 목차를 사용하면 특정 콘텐츠가 있는 영역을 빠르게 찾을 수 있으며 효율성은 선형적으로 증가합니다.

인덱싱 소개

먼저 명령줄을 열고 mongo를 입력하세요. 기본적으로 mongodb는 test라는 데이터베이스에 연결됩니다.

➜ ~ mongo

MongoDB shell version: 2.4.9
connecting to: test
> show collections
>

컬렉션/테이블 표시를 사용하여 데이터베이스가 비어 있는지 확인할 수 있습니다.

그런 다음 mongodb 명령줄 터미널에서 다음 코드를 실행하세요

> for(var i=0;i<100000;i++) {
... db.users.insert({username:&#39;user&#39;+i})
... }
> show collections
system.indexes
users
>

그런 다음 데이터베이스를 확인하고 더 많은 system.indexes와 사용자를 위한 두 개의 테이블이 있는데 전자는 소위 인덱스이고 후자는 새로 생성된 데이터베이스 테이블입니다.
이렇게 하면 사용자 테이블에 100,000개의 데이터가 있게 됩니다.

> db.users.find()
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e4"), "username" : "user0" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e5"), "username" : "user1" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e6"), "username" : "user2" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e7"), "username" : "user3" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e8"), "username" : "user4" }
{ "_id" : ObjectId("5694d5da8fad9e319c5b43e9"), "username" : "user5" }

이제 데이터를 찾아야 합니다. 예를 들어

> db.users.find({username: &#39;user1234&#39;})
{ "_id" : ObjectId("5694d5db8fad9e319c5b48b6"), "username" : "user1234" }

는 이 데이터를 성공적으로 찾았지만 자세한 정보를 알아야 하고 explain 메소드를 추가해야 합니다.

   
> db.users.find({username: &#39;user1234&#39;}).explain()
{
  "cursor" : "BasicCursor",
  "isMultiKey" : false,
  "n" : 1,
  "nscannedObjects" : 100000,
  "nscanned" : 100000,
  "nscannedObjectsAllPlans" : 100000,
  "nscannedAllPlans" : 100000,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 30,
  "indexBounds" : {
      
  },
  "server" : "root:27017"
}

여러 매개변수가 있습니다. 현재 우리는 두 항목 모두 "nscanned": 100000 및 "millis": 30에만 중점을 두고 있습니다.

nscanned는 이 쿼리가 완료되는 동안 mongodb에서 스캔한 총 문서 수를 나타냅니다. 컬렉션의 모든 문서가 스캔되고 총 시간이 30밀리초임을 알 수 있습니다.

데이터가 1천만 개라면 문서를 쿼리할 때마다 순회하게 됩니다. 글쎄, 시간도 상당히 상당합니다.

이러한 쿼리에는 색인 생성이 매우 좋은 솔루션입니다.

> db.users.ensureIndex({"username": 1})

그럼 user1234

> db.users.ensureIndex({"username": 1})
> db.users.find({username: 'user1234'}).explain()
{
  "cursor" : "BtreeCursor username_1",
  "isMultiKey" : false,
  "n" : 1,
  "nscannedObjects" : 1,
  "nscanned" : 1,
  "nscannedObjectsAllPlans" : 1,
  "nscannedAllPlans" : 1,
  "scanAndOrder" : false,
  "indexOnly" : false,
  "nYields" : 0,
  "nChunkSkips" : 0,
  "millis" : 0,
  "indexBounds" : {
    "username" : [
      [
        "user1234",
        "user1234"
      ]
    ]
  },
  "server" : "root:27017"
}


를 검색하면 정말 100,000개가 아닌 1개의 데이터만 인덱스를 통해 발견되기 때문에 쿼리가 순식간에 완료됩니다.

물론 인덱스를 사용하면 비용이 발생합니다. 인덱스가 추가될 때마다 각 쓰기 작업(삽입, 업데이트, 삭제)에 더 많은 시간이 걸립니다. 데이터가 변경되면 문서를 업데이트해야 할 뿐만 아니라 레벨 컬렉션의 모든 인덱스도 업데이트되기 때문입니다. 따라서 mongodb는 각 컬렉션을 최대 64개의 인덱스로 제한합니다. 일반적으로 특정 컬렉션에는 인덱스가 2개 이상 있어서는 안 됩니다.

Tips

매우 일반적인 쿼리이거나 이 쿼리로 인해 성능 병목 현상이 발생하는 경우 특정 필드(예: 사용자 이름)에 인덱스를 생성하는 것이 매우 좋은 선택입니다. 그러나 이 필드가 관리자(쿼리하는 데 걸리는 시간에 관심이 없는)가 사용하는 쿼리에만 사용되는 경우 색인을 생성해서는 안 됩니다.

복합 색인

색인의 값은 일정한 순서로 배열되어 있으므로 색인 키를 사용하여 문서를 정렬하는 것이 매우 빠릅니다.

db.users.find().sort({'age': 1, 'username': 1})


여기서는 먼저 나이를 기준으로 정렬한 다음 사용자 이름을 기준으로 정렬하므로 여기서 사용자 이름은 아무런 역할을 하지 않습니다. . 큰. 이 정렬을 최적화하려면 나이와 사용자 이름에 대한 색인을 생성해야 할 수도 있습니다.

db.users.ensureIndex({'age':1, '사용자 이름': 1})
이렇게 하면 복합 인덱스(여러 필드에 구축된 인덱스)가 생성되는데, 이는 쿼리 조건에 여러 키가 포함된 경우 매우 유용합니다.

복합 인덱스가 설정된 후 각 인덱스 항목에는 나이 필드와 사용자 이름 필드가 포함되며 디스크에 있는 문서의 저장 위치를 ​​가리킵니다.
이때 연령 항목은 엄격한 오름차순으로 정렬됩니다. 연령이 동일할 경우 사용자 이름별로 오름차순으로 정렬됩니다.

쿼리 방법

포인트 쿼리

는 단일 값을 쿼리하는 데 사용됩니다(이 값을 포함하는 문서가 여러 개 있을 수 있음)

db.users.find({'age': 21}).sort( {'username ': -1})


이미 복합 인덱스를 설정했기 때문에 하나의 나이와 하나의 사용자 이름을 인덱스를 설정할 때 포인트 쿼리를 사용하여 {age: 21 }, 아직 10만 개의 데이터가 있다고 가정하면 21세의 사람들이 많을 수 있으므로 1개 이상의 데이터가 발견될 것이다. 그런 다음 sort({'사용자 이름': -1}) 이러한 데이터를 원래 의도인 역순으로 정렬합니다. 그러나 인덱스를 생성할 때 '사용자 이름'을 잊지 마십시오. 1은 오름차순입니다(작은 것부터 큰 것까지). 역순을 얻으려면 데이터의 마지막 인덱스에서 시작하여 원하는 것을 얻기 위해 순회하면 됩니다. 결과.

정렬 방향은 중요하지 않습니다. mongodb는 어떤 방향에서든 인덱스를 탐색할 수 있습니다.
요약하자면, 복합 인덱스는 나이를 직접 찾아 결과를 정렬하고 결과를 반환할 필요 없이 포인트 쿼리에 매우 효율적입니다.

다중 값 쿼리(다중 값 쿼리)

db.users.find({'age': {"$gte": 21, "$lte": 30}})


여러 항목 찾기 값이 일치하는 문서. 다중 값 쿼리는 다중 포인트 쿼리로도 이해할 수 있습니다.
위와 같이 21세에서 30세 사이의 나이를 찾고 싶습니다. monogdb는 일치하는 결과를 얻기 위해 인덱스의 첫 번째 키 "age"를 사용하며 결과는 일반적으로 인덱스 순서로 정렬됩니다.

db.users.find({'age': {"$gte": 21, "$lte": 30}}).sort({'username': 1})


与上一个类似,这次需要对结果排序。
在没有sort时,我们查询的结果首先是根据age等于21,age等于22..这样从小到大排序,当age等于21有多个时,在进行usernameA-Z(0-9)这样排序。所以,sort({'username': 1}),要将所有结果通过名字升序排列,这次不得不先在内存中进行排序,然后返回。效率不如上一个高。

当然,在文档非常少的情况,排序也花费不了多少时间。
如果结果集很大,比如超过32MB,MongoDB会拒绝对如此多的数据进行排序工作。

还有另外一种解决方案

也可以建立另外一个索引{'username': 1, 'age': 1}, 如果先对username建立索引,当再sortusername,相当没有进行排序。但是需要在整个文档查找age等于21的帅哥美女,所以搜寻时间就长了。

但哪个效率更高呢?

如果建立多个索引,如何选择使用哪个呢?
效率高低是分情况的,如果在没有限制的情况下,不用进行排序但需要搜索整个集合时间会远超过前者。但是在返回部分数据(比如limit(1000)),新的赢家就产生了。

   
>db.users.find({&#39;age&#39;: {"$gte": 21, "$lte": 30}}).
sort({username&#39;: 1}).
limit(1000).
hint({&#39;age&#39;: 1, &#39;username&#39;: 1})
explain()[&#39;millis&#39;]
2031ms
  
>db.users.find({&#39;age&#39;: {"$gte": 21, "$lte": 30}}).
sort({username&#39;: 1}).
limit(1000).
hint({&#39;username&#39;: 1, &#39;age&#39;: 1}).
explain()[&#39;millis&#39;]
181ms


其中可以使用hint指定要使用的索引。
所以这种方式还是很有优势的。比如一般场景下,我们不会把所有的数据都取出来,只是去查询最近的,所以这种效率也会更高。

索引类型

唯一索引

可以确保集合的每个文档的指定键都有唯一值。

db.users.ensureIndex({&#39;username&#39;: 1, unique: 
true})


比如使用mongoose框架,在定义schema时,即可指定unique: true.
如果插入2个相同都叫张三的数据,第二次插入的则会失败。_id即为唯一索引,并且不能删除。

稀疏索引

使用sparse可以创建稀疏索引

>db.users.ensureIndex({&#39;email&#39;: 1}, {&#39;unique&#39;: true, &#39;sparse&#39;: 
true})

索引管理

system.indexes集合中包含了每个索引的详细信息

db.system.indexes.find()

1.ensureIndex()创建索引

db.users.ensureIndex({&#39;username&#39;: 
1})


后台创建索引,这样数据库再创建索引的同时,仍然能够处理读写请求,可以指定background选项。

db.test.ensureIndex({"username":1},{"background":true})

2.getIndexes()查看索引

db.collectionName.getIndexes()
db.users.getIndexes()
[
  {
    "v" : 1,
    "key" : {
      "_id" : 1
    },
    "ns" : "test.users",
    "name" : "_id_"
  },
  {
    "v" : 1,
    "key" : {
      "username" : 1
    },
    "ns" : "test.users",
    "name" : "username_1"
  }
]


其中v字段只在内部使用,用于标识索引版本。

3.dropIndex删除索引

> db.users.dropIndex("username_1")
{ "nIndexesWas" : 2, "ok" : 1 }


全选复制放进笔记> db.users.dropIndex({"username":1})

以上内容就是MongoDB索引的使用详解,希望对大家有帮助。

相关推荐:

MongoDB的技巧与注意事项汇总

MongoDB索引概念及使用详解

Dex – MongoDB索引优化工具

위 내용은 MongoDB 인덱스를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.