В настоящее время я работаю с MongoDB 3.6.1 и сталкиваюсь со странным поведением, используя составной индекс .У меня есть коллекция с примерно 2 миллионами документов, и вот структура одного документа:
{
"_id" : ObjectId("5af478b408e0f42946ff14ec"),
"IpStart" : NumberLong(50331649),
"IpEnd" : NumberLong(54525951),
"Latitude" : "47.634",
"Longitude" : "-122.342",
"PostalCode" : "98109",
"MarketId" : 308,
"City" : "Seattle",
"State" : "WA"
}
И мои индексы выглядят так:
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "locations_fact.IpRangeLocations"
},
{
"v" : 2,
"unique" : true,
"key" : {
"IpStart" : 1,
"IpEnd" : 1
},
"name" : "IpStart_1_IpEnd_1",
"ns" : "locations_fact.IpRangeLocations"
}
]
Когда я сделал этот запрос:
db.IpRangeLocations.find({"IpStart":{$lt:1209192009}, "IpEnd":{$gt:1209192009}}).explain("executionStats")
Я получил ответ в течение 5 секунд, когда он проверяет только ключи 955043.
Вот ответ с включенной опцией объяснения:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "locations_fact.IpRangeLocations",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"IpStart" : {
"$lt" : 1209192009.0
}
},
{
"IpEnd" : {
"$gt" : 1209192009.0
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"IpStart" : 1,
"IpEnd" : 1
},
"indexName" : "IpStart_1_IpEnd_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"IpStart" : [],
"IpEnd" : []
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"IpStart" : [
"[-inf.0, 1209192009.0)"
],
"IpEnd" : [
"(1209192009.0, inf.0]"
]
}
}
},
"rejectedPlans" : []
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 5019,
"totalKeysExamined" : 955043,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 4823,
"works" : 955043,
"advanced" : 1,
"needTime" : 955041,
"needYield" : 0,
"saveState" : 7530,
"restoreState" : 7530,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 4773,
"works" : 955043,
"advanced" : 1,
"needTime" : 955041,
"needYield" : 0,
"saveState" : 7530,
"restoreState" : 7530,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"IpStart" : 1,
"IpEnd" : 1
},
"indexName" : "IpStart_1_IpEnd_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"IpStart" : [],
"IpEnd" : []
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"IpStart" : [
"[-inf.0, 1209192009.0)"
],
"IpEnd" : [
"(1209192009.0, inf.0]"
]
},
"keysExamined" : 955043,
"seeks" : 955042,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "SOLANOD",
"port" : 27017,
"version" : "3.6.1",
"gitVersion" : "025d4f4fe61efd1fb6f0005be20cb45a004093d1"
},
"ok" : 1.0
}
Затем, когда я удалил составной индекс, я получил лучшие результаты (1,932 с), но он проверяет 1726879 документов (больше, чем с помощью индекса)
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "locations_fact.IpRangeLocations",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"IpStart" : {
"$lt" : 1209192009.0
}
},
{
"IpEnd" : {
"$gt" : 1209192009.0
}
}
]
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"IpStart" : {
"$lt" : 1209192009.0
}
},
{
"IpEnd" : {
"$gt" : 1209192009.0
}
}
]
},
"direction" : "forward"
},
"rejectedPlans" : []
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 1916,
"totalKeysExamined" : 0,
"totalDocsExamined" : 1726879,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"IpStart" : {
"$lt" : 1209192009.0
}
},
{
"IpEnd" : {
"$gt" : 1209192009.0
}
}
]
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 1697,
"works" : 1726881,
"advanced" : 1,
"needTime" : 1726879,
"needYield" : 0,
"saveState" : 13531,
"restoreState" : 13531,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 1726879
}
},
"serverInfo" : {
"host" : "SOLANOD",
"port" : 27017,
"version" : "3.6.1",
"gitVersion" : "025d4f4fe61efd1fb6f0005be20cb45a004093d1"
},
"ok" : 1.0
}
Также я попытался создать отдельный индекс (один для IpStart и другойодин для IpEnd) без улучшений.
Когда я сделал тот же запрос на SQL, используя оператор Между и с составным индексом:
SELECT * FROM [dbo].[ip_range_location] WHERE ipaddress BETWEEN ip_start AND ip_end
, это занимает не более 300 мс.
Я ожидал, что Монго ответит до 100 мс, но я не уверен, что здесь будет не так.
Любая идея великолепна, спасибо