Indeksstrategi og validering af forespørgselsplanen
De definerer det komplette indeksæt for skemaet, validerer hvert indeks med explain() og fjerner overflødige indekser.
Indeksstrategi og validering af forespørgselsplanen er en gratis MongoDB Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i MongoDB Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. MongoDB Academy-kurset indeholder 4 lektioner i alt.
Oversigt over indeksstrategien
En indeksstrategi er en bevidst plan for, hvilke indekser der skal oprettes, ikke en tilfældig samling af indekser, der tilføjes, hver gang en forespørgsel er langsom. Alle indekser har en omkostning: De gør læsninger hurtigere, men skrivninger langsommere (hver skrivning skal opdatere alle indekser i samlingen) og bruger RAM (indekser skal kunne være i arbejdssættet). En god strategi opretter det mindst mulige antal indekser, der dækker alle hyppige adgangsmønstre.
Begynd med registret over adgangsmønstre
Knyt hvert hyppigt adgangsmønster, der blev identificeret under kravanalysen, til et foreslået indeks. Dokumentér indeksfelterne, sorteringsretningen og formålet. For vores e-handelsplatform bruger produktsiden { slug: 1 }; kategorilisten bruger { categoryId: 1, price: 1, _id: 1 } til keyset-sideinddeling; ordrehistorikken bruger { userId: 1, createdAt: -1 }. Dette register forhindrer overflødige indekser og manglende dækning.
// Index register for e-commerce capstone
const indexRegister = [
{ collection: 'products', index: { slug: 1 }, unique: true, covers: 'product page' },
{ collection: 'products', index: { categoryId: 1, price: 1, _id: 1 }, unique: false, covers: 'category listing + keyset' },
{ collection: 'products', index: { 'vendor._id': 1 }, unique: false, covers: 'vendor store page' },
{ collection: 'orders', index: { userId: 1, createdAt: -1 }, unique: false, covers: 'user order history' },
{ collection: 'orders', index: { status: 1, createdAt: 1 }, unique: false, covers: 'fulfillment queue' },
{ collection: 'reviews', index: { productId: 1, createdAt: -1 }, unique: false, covers: 'reviews by product' }
]Anvendelse af ESR-reglen på sammensatte indekser
ESR-reglen (Equality → Sort → Range) bestemmer feltrækkefølgen i sammensatte indekser. Placér først filterfelter med lighed (de reducerer mængden af kandidater mest), derefter sorteringsfelter (så MongoDB kan udføre sorteringen fra indekset), og til sidst filterfelter med intervaller. Denne rækkefølge maksimerer indeksdækningen og gør det muligt for MongoDB at undgå et sorteringstrin i hukommelsen.
// Query: products in category, price under 200, sorted by price
// E = categoryId (equality), S = price (sort), R = none
// Correct ESR order:
db.products.createIndex({ categoryId: 1, price: 1 })
// Query: orders by user, status = 'processing', sorted by date
// E = userId (equality) + status (equality), S = createdAt
db.orders.createIndex({ userId: 1, status: 1, createdAt: -1 })
// Verify with explain
db.orders.find({ userId: userId, status: 'processing' })
.sort({ createdAt: -1 })
.explain('executionStats')Oprettelse af indekssættet til afslutningsprojektet
Opret alle planlagte indekser i ét script, så de kan anvendes atomisk i ethvert miljø (lokalt, staging eller produktion). Kør oprettelsen af indekser i baggrunden ({ background: true } i ældre versioner; som standard i baggrunden i MongoDB 4.2+) så samlingen ikke blokeres under oprettelsen. Test altid oprettelsen af indekser i et stagingmiljø, før du kører den på produktionsdata.
// indexes/setup.js — run once per environment
async function createIndexes(db) {
await db.collection('products').createIndexes([
{ key: { slug: 1 }, unique: true },
{ key: { categoryId: 1, price: 1, _id: 1 } },
{ key: { tags: 1 } },
{ key: { 'vendor._id': 1 } }
])
await db.collection('orders').createIndexes([
{ key: { userId: 1, createdAt: -1 } },
{ key: { status: 1, createdAt: 1 } },
{ key: { 'items.productId': 1 } }
])
await db.collection('reviews').createIndexes([
{ key: { productId: 1, createdAt: -1 } },
{ key: { userId: 1 } }
])
console.log('All indexes created')
}Validering af indekser med explain()
Efter oprettelsen af indekser skal du validere hver kritisk forespørgsel med .explain('executionStats'). Se efter fire vigtige felter i outputtet: winningPlan.inputStage.stage skal være 'IXSCAN' (ikke 'COLLSCAN'); totalKeysExamined skal ligge tæt på nReturned; totalDocsExamined skal være lig med nReturned for en dækket forespørgsel; og executionTimeMillis skal være tilstrækkeligt lav.
// Validate product category listing query
const result = await db.collection('products')
.find({ categoryId: new ObjectId('...'), price: { $lte: 200 } })
.sort({ price: 1 })
.explain('executionStats')
const { winningPlan, totalKeysExamined, totalDocsExamined, nReturned, executionTimeMillis } = result.executionStats
console.log('Stage:', winningPlan.inputStage.stage) // IXSCAN or COLLSCAN
console.log('Keys / Docs / Returned:', totalKeysExamined, totalDocsExamined, nReturned)
console.log('Time ms:', executionTimeMillis)Dækkede forespørgsler: Eliminering af FETCH
En dækket forespørgsel er en forespørgsel, hvor alle udvalgte felter findes i selve indekset — MongoDB behøver aldrig hente det faktiske dokument. Dækkede forespørgsler er ekstremt hurtige, fordi de kun læser indekset (som er mindre og kan være i RAM) i stedet for at indlæse dokumenter. Til produktsidens listevisning, som kun behøver slug, name, price og imageUrl, skal du oprette et indeks, der indeholder alle disse felter.
// Covered index for product listing cards
db.products.createIndex({
categoryId: 1,
price: 1,
name: 1,
slug: 1,
imageUrl: 1
})
// This query is now covered — no FETCH stage
db.products.find(
{ categoryId: ObjectId('...') },
{ _id: 0, name: 1, slug: 1, price: 1, imageUrl: 1 }
).sort({ price: 1 }).explain('executionStats')
// Verify: no FETCH stage in winningPlanIdentificering af overflødige indekser
Indekser er dyre — hvert indeks øger skriveomkostningerne. Et overflødigt indeks er et indeks, hvis præfiks er identisk med et andet indeks. Hvis du har { userId: 1 } og { userId: 1, createdAt: -1 }, er det første overflødigt, fordi det sammensatte indeks opfylder alle de forespørgsler, som enkeltfeltsindekset ville opfylde. Brug db.collection.aggregate([{ $indexStats: {} }]) til at se, hvilke indekser der har få adgange, og overvej at slette dem.
// Find rarely used indexes
db.orders.aggregate([{ $indexStats: {} }])
.then(stats => {
stats.forEach(s => {
console.log(s.name, 'accesses:', s.accesses.ops)
})
})
// Indexes with ops = 0 since last restart may be candidates for removal
// Drop a redundant index
db.orders.dropIndex('userId_1') // if userId_1_createdAt_-1 already covers itTekstindekset til produktsøgning
Fuldtekstsøgning i produktnavne, beskrivelser og tags kræver et tekstindeks. Opret et sammensat tekstindeks, der dækker alle søgbare tekstfelter. Tilføj indstillingen weights for at rangere træffere i navnet højere end træffere i beskrivelsen. Kontrollér med explain, at forespørgsler med $text bruger trinnet TEXT og returnerer resultater sorteret efter textScore.
// Text index for product search
db.products.createIndex(
{ name: 'text', description: 'text', tags: 'text' },
{ weights: { name: 10, tags: 5, description: 1 }, name: 'product_text_idx' }
)
// Text search query with relevance sorting
db.products.find(
{ $text: { $search: 'wireless noise cancelling' } },
{ score: { $meta: 'textScore' } }
).sort({ score: { $meta: 'textScore' } }).limit(20)Sparse- og delvise indekser til valgfrie felter
Nogle dokumenter har valgfrie felter, som kun findes i en del af dokumenterne. Opret et delvist indeks med partialFilterExpression for kun at indeksere de dokumenter, hvor feltet findes og opfylder betingelsen. Det holder indekset lille og effektivt sammenlignet med at indeksere null-værdier i et sparse-indeks. For ordrer med feltet couponCode (som kun findes i 10 % af ordrerne) er et delvist indeks ideelt.
// Partial index: only index orders that have a coupon
db.orders.createIndex(
{ couponCode: 1 },
{
partialFilterExpression: { couponCode: { $exists: true } },
name: 'orders_with_coupon'
}
)
// Partial index: only index active products
db.products.createIndex(
{ categoryId: 1, price: 1 },
{
partialFilterExpression: { isActive: true },
name: 'active_products_by_category'
}
)Unikke indekser til dataintegritet
Unikke indekser forhindrer duplikerede data på databaseniveau — det sikreste sted at håndhæve entydighed. Opret unikke indekser på felter, der skal være entydige: user.email, product.slug, vendor.slug. Et unikt indeks er mere pålideligt end kontroller på applikationsniveau, fordi det forhindrer dubletter selv ved race conditions eller samtidige skrivninger fra flere instanser af applikationen.
// Unique indexes for business constraints
db.users.createIndex({ email: 1 }, { unique: true })
db.products.createIndex({ slug: 1 }, { unique: true })
db.vendors.createIndex({ slug: 1 }, { unique: true })
// Partial unique index: unique email only for verified users
db.users.createIndex(
{ email: 1 },
{
unique: true,
partialFilterExpression: { emailVerified: true }
}
)Vedligeholdelse og overvågning af indekser
Indekser kræver løbende vedligeholdelse. Brug MongoDB Compass eller Atlas Performance Advisor til at overvåge forespørgselsydelsen og automatisk modtage forslag til indekser. Performance Advisor analyserer langsomme forespørgsler (dem, der overskrider tærsklen slowMs) og foreslår sammensatte indekser for at forbedre dem. Gennemgå jævnligt $indexStats for at fjerne indekser, der ikke længere bruges, efterhånden som forespørgselsmønstrene udvikler sig.
// Enable profiling to capture slow queries
db.setProfilingLevel(1, { slowms: 50 }) // log queries > 50ms
// Query the profiler for the slowest recent operations
db.system.profile.find().sort({ millis: -1 }).limit(10).pretty()
// Check index usage statistics (reset on mongod restart)
db.products.aggregate([{ $indexStats: {} }])Hurtigt tjek
Test din forståelse af begreberne i MongoDB & NoSQL Databases fra denne lektion.
Opsummering af lektionen
I denne lektion lærte du, at ESR-reglen (Equality → Sort → Range) bestemmer den optimale feltrækkefølge i sammensatte indekser for maksimal dækning, at explain('executionStats') validerer, at forespørgsler bruger IXSCAN, og viser forholdet mellem undersøgte og returnerede dokumenter, og at $indexStats identificerer overflødige eller ubrugte indekser, som bør fjernes for at reducere skriveomkostningerne. Nu udarbejder vi skaleringsplanen — fra replikasæt til sharded cluster.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “Indeksstrategi og validering af forespørgselsplanen” gratis?
Ja — hele teksten til “Indeksstrategi og validering af forespørgselsplanen” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af MongoDB Academy-kurset, skal du opgradere til CoddyKit PRO. MongoDB Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Indeksstrategi og validering af forespørgselsplanen”?
De definerer det komplette indeksæt for skemaet, validerer hvert indeks med explain() og fjerner overflødige indekser. Du øver dig i MongoDB Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på MongoDB Academy?
Der kræves ingen tidligere erfaring. MongoDB Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Indeksstrategi og validering af forespørgselsplanen”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne MongoDB Academy-lektion?
Ja. Alle MongoDB Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- Kravsanalyse og skemadesign
- Indeksstrategi og validering af forespørgselsplanen
- Skaleringsplan: Fra replikasæt til sharded klynge
- Sikkerhedshærdning og tjekliste til produktion