부분 인덱스
이 페이지의 내용
부분 인덱스는 지정된 필터 표현식을 충족하는 컬렉션의 문서만 인덱싱합니다. 컬렉션에 있는 문서의 하위 집합을 인덱싱하면 부분 인덱스의 스토리지 요구 사항이 줄어들고 인덱스 생성 및 유지 관리에 드는 성능 비용이 절감됩니다.
부분 인덱스 생성하기
partial
인덱스를 생성하려면 partialFilterExpression
옵션과 함께 db.collection.createIndex()
메서드를 사용합니다. partialFilterExpression
옵션은 다음을 사용하여 필터 조건을 지정하는 문서를 허용합니다.
예를 들어, 다음 작업은 rating
필드가 5보다 큰 문서만 인덱싱하는 복합 인덱스를 만듭니다.
db.restaurants.createIndex( { cuisine: 1, name: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } } )
모든 MongoDB 인덱스 유형에 partialFilterExpression
옵션을 지정할 수 있습니다. 시계열 컬렉션의 TTL 인덱스에 partialFilterExpression
를 지정하는 경우 컬렉션의 metaField
에 대해서만 필터링할 수 있습니다.
행동
쿼리 적용 범위
MongoDB는 인덱스를 사용하여 불완전한 결과 집합이 생성되는 경우 쿼리 또는 정렬 작업에 부분 인덱스를 사용하지 않습니다.
부분 인덱스를 사용하려면 쿼리가 필터 표현식 (또는 필터 표현식의 부분 집합을 지정하는 수정된 필터 표현식)을 쿼리 조건의 일부로 포함해야 합니다.
예를 들어 다음 인덱스가 있다고 가정해 보겠습니다.
db.restaurants.createIndex( { cuisine: 1 }, { partialFilterExpression: { rating: { $gt: 5 } } } )
다음 쿼리는 쿼리 조건에 인덱스 필터 표현식 rating: { $gt: 5
}
에 부합하는 문서의 하위 집합과 일치하는 조건 rating: { $gte: 8 }
이 포함되어 있으므로 해당 인덱스를 사용할 수 있습니다.
db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )
하지만 다음 쿼리에서는 cuisine
필드의 부분 인덱스를 사용할 수 없습니다. 인덱스를 사용하면 결과 집합이 불완전해지기 때문입니다. 특히 쿼리 조건자에는 조건 rating: { $lt: 8 }
이 포함되어 있는 반면, 인덱스에는 필터 rating: { $gt:
5 }
가 있습니다. 즉, { cuisine: "Italian", rating: { $lt: 8 }
}
쿼리는 인덱싱된 문서보다 더 많은 문서 (예: 평점이 1인 이탈리아 레스토랑)와 일치합니다.
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
마찬가지로, 다음 쿼리는 쿼리 조건자에 필터 표현식이 포함되어 있지 않고 인덱스를 사용하면 불완전한 결과 집합이 반환되기 때문에 부분 인덱스를 사용할 수 없습니다.
db.restaurants.find( { cuisine: "Italian" } )
Sparse 인덱스와 비교
부분 인덱스는 Sparse 인덱스보다 선호 되어야 합니다. 부분 인덱스는 다음과 같은 이점을 제공합니다.
어떤 문서가 색인화되는지 더 효과적으로 제어할 수 있음.
Sparse 인덱스에서 제공하는 기능의 상위 집합.
Sparse 인덱스는 인덱스된 필드의 존재 여부에 전적으로 기반하여 문서를 선택합니다. 복합 인덱스의 경우 인덱스된 필드의 존재 여부에 따릅니다.
부분 인덱스는 지정된 필터를 기반으로 인덱스 항목을 결정합니다. 필터는 인덱스 키 이외의 필드를 포함할 수 있으며 존재 확인 이외의 조건을 지정할 수 있습니다. 예를 들어, 부분 인덱스는 Sparse 인덱스와 동일한 동작을 구현할 수 있습니다.
db.contacts.createIndex( { name: 1 }, { partialFilterExpression: { name: { $exists: true } } } )
이 부분 인덱스는 name
필드에 대해 Sparse 인덱스와 동일한 쿼리를 지원합니다.
그러나 부분 인덱스는 인덱스 키 이외의 필드에 필터 표현식을 지정할 수도 있습니다. 예를 들어 다음 작업은 부분 인덱스을 생성합니다. 여기서 인덱스는 name
필드에 있지만 필터 표현식은 email
필드에 있습니다.
db.contacts.createIndex( { name: 1 }, { partialFilterExpression: { email: { $exists: true } } } )
쿼리 옵티마이저가 이 부분 인덱스를 선택하려면 쿼리 조건이 name
필드에 대한 조건을 포함해야 하며 email
필드에 대해 null이 아닌 일치도 포함해야 합니다.
예를 들어, 다음 쿼리는 name
필드에 대한 조건과 email
필드에 대한 null이 아닌 일치 항목을 모두 포함하므로 인덱스를 사용할 수 있습니다.
db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )
그러나 다음 쿼리는 필터 표현식 { email: { $exists: true } }
에서 허용되지 않는 email
필드에 null 일치를 포함하고 있기 때문에 인덱스를 사용할 수 없습니다.
db.contacts.find( { name: "xyz", email: { $exists: false } } )
부분 TTL 인덱스
부분 인덱스는 TTL 인덱스일 수도 있습니다. 부분 TTL 인덱스는 지정된 필터 표현식과 일치하며 해당 문서만 만료됩니다. 자세한 내용은 필터 조건이 있는 문서 만료를 참조하세요.
제한 사항
partialFilterExpression
옵션과sparse
옵션을 모두 지정할 수 없습니다._id
인덱스는 부분 인덱스가 될 수 없습니다.샤드 키 인덱스는 부분 인덱스가 될 수 없습니다.
클라이언트 사이드 필드 수준 암호화 또는 Queryable Encryption을 사용하는 경우
partialFilterExpression
은 암호화된 필드를 참조할 수 없습니다.
동등한 인덱스
MongoDB 7.3 부터는 데이터 정렬을 사용하는 동일한 인덱스 키와 동일한 부분 표현식을 가진 부분 인덱스를 생성할 수 없습니다.
기존의 동등한 인덱스가 있는 MongoDB 7.3 데이터베이스의 경우 인덱스는 유지되지만 첫 번째 동등한 인덱스만 쿼리에 사용됩니다. 이는 MongoDB 7.3 이전 버전과 동일한 동작입니다.
예시 는 등가 인덱스 예시를 참조하세요.
예시
컬렉션에 대한 부분 인덱스 만들기
다음과 비슷한 문서가 포함된 restaurants
컬렉션이 있다고 가정해 봅시다.
{ "_id" : ObjectId("5641f6a7522545bc535b5dc9"), "address" : { "building" : "1007", "coord" : [ -73.856077, 40.848447 ], "street" : "Morris Park Ave", "zipcode" : "10462" }, "borough" : "Bronx", "cuisine" : "Bakery", "rating" : { "date" : ISODate("2014-03-03T00:00:00Z"), "grade" : "A", "score" : 2 }, "name" : "Morris Park Bake Shop", "restaurant_id" : "30075445" }
rating.grade
필드가 A
인 문서의 인덱스만 생성하도록 선택하여 borough
및 cuisine
필드에 부분 인덱스를 추가할 수 있습니다.
db.restaurants.createIndex( { borough: 1, cuisine: 1 }, { partialFilterExpression: { 'rating.grade': { $eq: "A" } } } )
그런 다음 restaurants
컬렉션에 대한 다음 쿼리는 부분 인덱스를 사용하여 rating.grade
가 A
인 Bronx의 레스토랑을 반환합니다.
db.restaurants.find( { borough: "Bronx", 'rating.grade': "A" } )
그러나 다음 쿼리는 쿼리 조건자에 rating.grade
필드가 포함되어 있지 않기 때문에 부분 인덱스를 사용할 수 없습니다.
db.restaurants.find( { borough: "Bronx", cuisine: "Bakery" } )
Unique 제약 조건이 있는 부분 인덱스
부분 인덱스는 지정된 필터 표현식을 충족하는 컬렉션의 문서만 인덱싱합니다. partialFilterExpression
과 고유 (Unique) 제약 조건을 모두 지정하는 경우 고유 제약 조건은 필터 표현식을 충족하는 문서에만 적용됩니다. 고유 제약 조건이 있는 부분 인덱스는 문서가 필터 기준을 충족하지 않는 경우 고유 제약 조건을 충족하지 않는 문서의 삽입을 막지 않습니다.
예를 들어 users
컬렉션에는 다음과 같은 문서가 포함되어 있습니다.
{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 } { "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 } { "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }
다음 작업은 username
필드에 대한 고유 제약 조건과 부분 필터 식 age: { $gte: 21 }
을 지정하는 인덱스를 생성합니다.
db.users.createIndex( { username: 1 }, { unique: true, partialFilterExpression: { age: { $gte: 21 } } } )
지정된 사용자 이름을 가진 문서가 이미 존재하고 age
필드가 21
보다 크므로 인덱스는 다음 문서의 삽입을 막습니다.
db.users.insertMany( [ { username: "david", age: 27 }, { username: "amanda", age: 25 }, { username: "rajiv", age: 32 } ] )
하지만 고유 제약 조건은 age
21보다 크거나 같은 문서에만 적용되므로 중복된 사용자 이름이 있는 다음 문서는 허용됩니다.
db.users.insertMany( [ { username: "david", age: 20 }, { username: "amanda" }, { username: "rajiv", age: null } ] )
등가 인덱스 예시
MongoDB 7.3 부터는 데이터 정렬을 사용하는 동일한 인덱스 키와 동일한 부분 표현식을 가진 부분 인덱스를 생성할 수 없습니다.
기존의 동등한 인덱스가 있는 MongoDB 7.3 데이터베이스의 경우 인덱스는 유지되지만 첫 번째 동등한 인덱스만 쿼리에 사용됩니다. 이는 MongoDB 7.3 이전 버전과 동일한 동작입니다.
이전 MongoDB 버전에서는 두 개의 동등한 인덱스를 생성할 수 있습니다. 다음 예시 에서는 pizzas
컬렉션 과 index0
및 index1
라는 두 개의 동등한 인덱스를 만듭니다.
// Create the pizzas collection db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] ) // Create two equivalent indexes with medium pizza sizes db.pizzas.createIndex( { type: 1 }, { name: "index0", partialFilterExpression: { size: "medium" }, collation: { locale: "en_US", strength: 1 } } ) db.pizzas.createIndex( { type: 1 }, { name: "index1", partialFilterExpression: { size: "MEDIUM" }, collation: { locale: "en_US", strength: 1 } } )
두 인덱스가 동일한 피자 크기를 지정하고 부분 필터하다 표현식 에서 텍스트 대소문자만 다르기 때문에 인덱스는 동일합니다. 쿼리에는 하나의 인덱스 만 사용되며, 이는 가장 먼저 생성된 인덱스 이며, 이전 예시 에서는 index0
입니다.
MongoDB 7.3 부터는 두 번째 인덱스 (index1
)를 생성할 수 없으며 이 오류가 반환됩니다.
MongoServerError: Index already exists with a different name: index0
7.3 이전 MongoDB 버전에서는 인덱스를 만들 수 있지만 이러한 쿼리에는 첫 번째 인덱스 (index0
)만 사용됩니다.
db.pizzas.find( { type: "cheese", size: "medium" } ).collation( { locale: "en_US", strength: 1 } ) db.pizzas.find( { type: "cheese", size: "MEDIUM" } ).collation( { locale: "en_US", strength: 1 } ) db.pizzas.find( { type: "cheese", size: "Medium" } ).collation( { locale: "en_US", strength: 1 } )