第135集MongoDB添加索引Java实战
|字数总计:5.7k|阅读时长:27分钟|阅读量:
1. MongoDB索引概述
MongoDB索引是提高查询性能的关键技术,通过创建索引可以显著提升数据查询速度。在Java应用中,合理使用MongoDB索引是优化数据库性能的重要手段。本文将详细介绍MongoDB索引的各种类型、创建方法、性能优化技巧以及在Java实战中的应用。
1.1 索引的核心作用
- 提升查询性能: 加速数据检索速度
- 优化排序操作: 提高排序查询效率
- 支持唯一约束: 确保数据唯一性
- 加速聚合操作: 提升聚合查询性能
- 减少内存使用: 降低查询时的内存消耗
1.2 索引类型
- 单字段索引: 在单个字段上创建索引
- 复合索引: 在多个字段上创建索引
- 多键索引: 在数组字段上创建索引
- 文本索引: 支持全文搜索的索引
- 地理空间索引: 支持地理位置查询的索引
- 哈希索引: 支持分片集群的索引
- 稀疏索引: 只包含有索引字段的文档
2. MongoDB索引基础操作
2.1 单字段索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
@Component public class SingleFieldIndexService { @Autowired private MongoTemplate mongoTemplate;
public void createAscendingIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建升序索引: " + fieldName); } catch (Exception e) { System.err.println("创建升序索引失败: " + e.getMessage()); } }
public void createDescendingIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.DESC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建降序索引: " + fieldName); } catch (Exception e) { System.err.println("创建降序索引失败: " + e.getMessage()); } }
public void createUniqueIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC).unique(); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建唯一索引: " + fieldName); } catch (Exception e) { System.err.println("创建唯一索引失败: " + e.getMessage()); } }
public void createSparseIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC).sparse(); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建稀疏索引: " + fieldName); } catch (Exception e) { System.err.println("创建稀疏索引失败: " + e.getMessage()); } }
public void createPartialIndex(String collectionName, String fieldName, String filterExpression) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC) .partial(Filter.parse(filterExpression)); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建部分索引: " + fieldName); } catch (Exception e) { System.err.println("创建部分索引失败: " + e.getMessage()); } } }
|
2.2 复合索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
@Component public class CompoundIndexService { @Autowired private MongoTemplate mongoTemplate;
public void createCompoundIndex(String collectionName, List<IndexField> fields) { try { Index index = new Index(); for (IndexField field : fields) { index.on(field.getFieldName(), field.getDirection()); } mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建复合索引: " + fields); } catch (Exception e) { System.err.println("创建复合索引失败: " + e.getMessage()); } }
public void createUserCompoundIndex(String collectionName) { try { Index index = new Index() .on("username", Sort.Direction.ASC) .on("email", Sort.Direction.ASC) .on("createdAt", Sort.Direction.DESC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建用户复合索引"); } catch (Exception e) { System.err.println("创建用户复合索引失败: " + e.getMessage()); } }
public void createOrderCompoundIndex(String collectionName) { try { Index index = new Index() .on("userId", Sort.Direction.ASC) .on("status", Sort.Direction.ASC) .on("createdAt", Sort.Direction.DESC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建订单复合索引"); } catch (Exception e) { System.err.println("创建订单复合索引失败: " + e.getMessage()); } }
public static class IndexField { private String fieldName; private Sort.Direction direction; public IndexField(String fieldName, Sort.Direction direction) { this.fieldName = fieldName; this.direction = direction; } public String getFieldName() { return fieldName; } public Sort.Direction getDirection() { return direction; } } }
|
2.3 多键索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
@Component public class MultiKeyIndexService { @Autowired private MongoTemplate mongoTemplate;
public void createArrayFieldIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建数组字段索引: " + fieldName); } catch (Exception e) { System.err.println("创建数组字段索引失败: " + e.getMessage()); } }
public void createTagsIndex(String collectionName) { try { Index index = new Index().on("tags", Sort.Direction.ASC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建标签索引"); } catch (Exception e) { System.err.println("创建标签索引失败: " + e.getMessage()); } }
public void createSkillsIndex(String collectionName) { try { Index index = new Index().on("skills", Sort.Direction.ASC); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建技能索引"); } catch (Exception e) { System.err.println("创建技能索引失败: " + e.getMessage()); } } }
|
2.4 文本索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
@Component public class TextIndexService { @Autowired private MongoTemplate mongoTemplate;
public void createTextIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC).named("text_" + fieldName); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建文本索引: " + fieldName); } catch (Exception e) { System.err.println("创建文本索引失败: " + e.getMessage()); } }
public void createMultiFieldTextIndex(String collectionName, List<String> fields) { try { Index index = new Index(); for (String field : fields) { index.on(field, Sort.Direction.ASC); } index.named("text_multi"); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建多字段文本索引: " + fields); } catch (Exception e) { System.err.println("创建多字段文本索引失败: " + e.getMessage()); } }
public void createArticleTextIndex(String collectionName) { try { Index index = new Index() .on("title", Sort.Direction.ASC) .on("content", Sort.Direction.ASC) .on("tags", Sort.Direction.ASC) .named("article_text_index"); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建文章文本索引"); } catch (Exception e) { System.err.println("创建文章文本索引失败: " + e.getMessage()); } }
public List<Document> searchText(String collectionName, String searchText) { try { TextCriteria criteria = TextCriteria.forDefaultLanguage().matching(searchText); Query query = TextQuery.queryText(criteria).sortByScore(); List<Document> results = mongoTemplate.find(query, Document.class, collectionName); System.out.println("文本搜索完成,找到 " + results.size() + " 条结果"); return results; } catch (Exception e) { System.err.println("文本搜索失败: " + e.getMessage()); return new ArrayList<>(); } } }
|
2.5 地理空间索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
@Component public class GeospatialIndexService { @Autowired private MongoTemplate mongoTemplate;
public void create2dIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC).named("2d_" + fieldName); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建2d索引: " + fieldName); } catch (Exception e) { System.err.println("创建2d索引失败: " + e.getMessage()); } }
public void create2dsphereIndex(String collectionName, String fieldName) { try { Index index = new Index().on(fieldName, Sort.Direction.ASC).named("2dsphere_" + fieldName); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建2dsphere索引: " + fieldName); } catch (Exception e) { System.err.println("创建2dsphere索引失败: " + e.getMessage()); } }
public void createLocationIndex(String collectionName) { try { Index index = new Index().on("location", Sort.Direction.ASC).named("location_2dsphere"); mongoTemplate.indexOps(collectionName).ensureIndex(index); System.out.println("成功创建位置索引"); } catch (Exception e) { System.err.println("创建位置索引失败: " + e.getMessage()); } }
public List<Document> findNearby(String collectionName, double longitude, double latitude, double maxDistance) { try { Point point = new Point(longitude, latitude); NearQuery nearQuery = NearQuery.near(point).maxDistance(maxDistance); List<Document> results = mongoTemplate.find(nearQuery, Document.class, collectionName); System.out.println("地理位置查询完成,找到 " + results.size() + " 条结果"); return results; } catch (Exception e) { System.err.println("地理位置查询失败: " + e.getMessage()); return new ArrayList<>(); } } }
|
3. 索引管理操作
3.1 索引查询和管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
|
@Component public class IndexManagementService { @Autowired private MongoTemplate mongoTemplate;
public List<IndexInfo> getAllIndexes(String collectionName) { try { IndexOperations indexOps = mongoTemplate.indexOps(collectionName); List<IndexInfo> indexes = indexOps.getIndexInfo(); System.out.println("集合 " + collectionName + " 共有 " + indexes.size() + " 个索引"); return indexes; } catch (Exception e) { System.err.println("获取索引列表失败: " + e.getMessage()); return new ArrayList<>(); } }
public boolean indexExists(String collectionName, String indexName) { try { IndexOperations indexOps = mongoTemplate.indexOps(collectionName); List<IndexInfo> indexes = indexOps.getIndexInfo(); for (IndexInfo index : indexes) { if (indexName.equals(index.getName())) { return true; } } return false; } catch (Exception e) { System.err.println("检查索引是否存在失败: " + e.getMessage()); return false; } }
public void dropIndex(String collectionName, String indexName) { try { IndexOperations indexOps = mongoTemplate.indexOps(collectionName); indexOps.dropIndex(indexName); System.out.println("成功删除索引: " + indexName); } catch (Exception e) { System.err.println("删除索引失败: " + e.getMessage()); } }
public void dropAllIndexes(String collectionName) { try { IndexOperations indexOps = mongoTemplate.indexOps(collectionName); indexOps.dropAllIndexes(); System.out.println("成功删除所有索引"); } catch (Exception e) { System.err.println("删除所有索引失败: " + e.getMessage()); } }
public void rebuildIndexes(String collectionName) { try { IndexOperations indexOps = mongoTemplate.indexOps(collectionName); indexOps.reindex(); System.out.println("成功重建索引"); } catch (Exception e) { System.err.println("重建索引失败: " + e.getMessage()); } }
public Map<String, Object> getIndexStats(String collectionName) { try { Document command = new Document("collStats", collectionName); Document result = mongoTemplate.getDb().runCommand(command); System.out.println("获取索引统计信息成功"); return result; } catch (Exception e) { System.err.println("获取索引统计信息失败: " + e.getMessage()); return new HashMap<>(); } } }
|
3.2 索引性能监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
@Component public class IndexPerformanceMonitor { @Autowired private MongoTemplate mongoTemplate;
public Map<String, Object> monitorIndexUsage(String collectionName) { try { Document command = new Document("collStats", collectionName); Document result = mongoTemplate.getDb().runCommand(command); Map<String, Object> indexStats = new HashMap<>(); if (result.containsKey("indexSizes")) { indexStats.put("indexSizes", result.get("indexSizes")); } if (result.containsKey("totalIndexSize")) { indexStats.put("totalIndexSize", result.get("totalIndexSize")); } System.out.println("索引使用情况监控完成"); return indexStats; } catch (Exception e) { System.err.println("监控索引使用情况失败: " + e.getMessage()); return new HashMap<>(); } }
public Map<String, Object> analyzeQueryPerformance(String collectionName, Query query) { try { Document explainResult = mongoTemplate.getCollection(collectionName) .find(query.getQueryObject()) .explain(); Map<String, Object> performance = new HashMap<>(); performance.put("executionTimeMillis", explainResult.get("executionTimeMillis")); performance.put("totalDocsExamined", explainResult.get("totalDocsExamined")); performance.put("totalKeysExamined", explainResult.get("totalKeysExamined")); performance.put("stage", explainResult.get("stage")); System.out.println("查询性能分析完成"); return performance; } catch (Exception e) { System.err.println("分析查询性能失败: " + e.getMessage()); return new HashMap<>(); } }
public List<Document> findSlowQueries(String collectionName, long threshold) { try { Query query = new Query(); query.addCriteria(Criteria.where("executionTimeMillis").gt(threshold)); List<Document> slowQueries = mongoTemplate.find(query, Document.class, collectionName); System.out.println("找到 " + slowQueries.size() + " 个慢查询"); return slowQueries; } catch (Exception e) { System.err.println("检查慢查询失败: " + e.getMessage()); return new ArrayList<>(); } } }
|
4. 实战应用示例
4.1 用户管理系统索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
@Component public class UserIndexConfiguration { @Autowired private MongoTemplate mongoTemplate;
@PostConstruct public void configureUserIndexes() { String collectionName = "users"; try { Index usernameIndex = new Index() .on("username", Sort.Direction.ASC) .unique() .named("idx_username_unique"); mongoTemplate.indexOps(collectionName).ensureIndex(usernameIndex); Index emailIndex = new Index() .on("email", Sort.Direction.ASC) .unique() .named("idx_email_unique"); mongoTemplate.indexOps(collectionName).ensureIndex(emailIndex); Index phoneIndex = new Index() .on("phone", Sort.Direction.ASC) .unique() .sparse() .named("idx_phone_unique"); mongoTemplate.indexOps(collectionName).ensureIndex(phoneIndex); Index statusIndex = new Index() .on("status", Sort.Direction.ASC) .named("idx_status"); mongoTemplate.indexOps(collectionName).ensureIndex(statusIndex); Index createdAtIndex = new Index() .on("createdAt", Sort.Direction.DESC) .named("idx_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(createdAtIndex); Index statusCreatedAtIndex = new Index() .on("status", Sort.Direction.ASC) .on("createdAt", Sort.Direction.DESC) .named("idx_status_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(statusCreatedAtIndex); Index textIndex = new Index() .on("username", Sort.Direction.ASC) .on("email", Sort.Direction.ASC) .named("idx_text_search"); mongoTemplate.indexOps(collectionName).ensureIndex(textIndex); System.out.println("用户集合索引配置完成"); } catch (Exception e) { System.err.println("用户集合索引配置失败: " + e.getMessage()); } } }
|
4.2 订单管理系统索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
@Component public class OrderIndexConfiguration { @Autowired private MongoTemplate mongoTemplate;
@PostConstruct public void configureOrderIndexes() { String collectionName = "orders"; try { Index orderNoIndex = new Index() .on("orderNo", Sort.Direction.ASC) .unique() .named("idx_order_no_unique"); mongoTemplate.indexOps(collectionName).ensureIndex(orderNoIndex); Index userIdIndex = new Index() .on("userId", Sort.Direction.ASC) .named("idx_user_id"); mongoTemplate.indexOps(collectionName).ensureIndex(userIdIndex); Index statusIndex = new Index() .on("status", Sort.Direction.ASC) .named("idx_status"); mongoTemplate.indexOps(collectionName).ensureIndex(statusIndex); Index createdAtIndex = new Index() .on("createdAt", Sort.Direction.DESC) .named("idx_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(createdAtIndex); Index userStatusIndex = new Index() .on("userId", Sort.Direction.ASC) .on("status", Sort.Direction.ASC) .named("idx_user_status"); mongoTemplate.indexOps(collectionName).ensureIndex(userStatusIndex); Index statusCreatedAtIndex = new Index() .on("status", Sort.Direction.ASC) .on("createdAt", Sort.Direction.DESC) .named("idx_status_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(statusCreatedAtIndex); Index userStatusCreatedAtIndex = new Index() .on("userId", Sort.Direction.ASC) .on("status", Sort.Direction.ASC) .on("createdAt", Sort.Direction.DESC) .named("idx_user_status_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(userStatusCreatedAtIndex); Index amountIndex = new Index() .on("amount", Sort.Direction.ASC) .named("idx_amount"); mongoTemplate.indexOps(collectionName).ensureIndex(amountIndex); System.out.println("订单集合索引配置完成"); } catch (Exception e) { System.err.println("订单集合索引配置失败: " + e.getMessage()); } } }
|
4.3 商品管理系统索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
@Component public class ProductIndexConfiguration { @Autowired private MongoTemplate mongoTemplate;
@PostConstruct public void configureProductIndexes() { String collectionName = "products"; try { Index productCodeIndex = new Index() .on("productCode", Sort.Direction.ASC) .unique() .named("idx_product_code_unique"); mongoTemplate.indexOps(collectionName).ensureIndex(productCodeIndex); Index nameIndex = new Index() .on("name", Sort.Direction.ASC) .named("idx_name"); mongoTemplate.indexOps(collectionName).ensureIndex(nameIndex); Index categoryIndex = new Index() .on("category", Sort.Direction.ASC) .named("idx_category"); mongoTemplate.indexOps(collectionName).ensureIndex(categoryIndex); Index priceIndex = new Index() .on("price", Sort.Direction.ASC) .named("idx_price"); mongoTemplate.indexOps(collectionName).ensureIndex(priceIndex); Index statusIndex = new Index() .on("status", Sort.Direction.ASC) .named("idx_status"); mongoTemplate.indexOps(collectionName).ensureIndex(statusIndex); Index createdAtIndex = new Index() .on("createdAt", Sort.Direction.DESC) .named("idx_created_at"); mongoTemplate.indexOps(collectionName).ensureIndex(createdAtIndex); Index categoryStatusIndex = new Index() .on("category", Sort.Direction.ASC) .on("status", Sort.Direction.ASC) .named("idx_category_status"); mongoTemplate.indexOps(collectionName).ensureIndex(categoryStatusIndex); Index categoryPriceIndex = new Index() .on("category", Sort.Direction.ASC) .on("price", Sort.Direction.ASC) .named("idx_category_price"); mongoTemplate.indexOps(collectionName).ensureIndex(categoryPriceIndex); Index textIndex = new Index() .on("name", Sort.Direction.ASC) .on("description", Sort.Direction.ASC) .named("idx_text_search"); mongoTemplate.indexOps(collectionName).ensureIndex(textIndex); Index tagsIndex = new Index() .on("tags", Sort.Direction.ASC) .named("idx_tags"); mongoTemplate.indexOps(collectionName).ensureIndex(tagsIndex); System.out.println("商品集合索引配置完成"); } catch (Exception e) { System.err.println("商品集合索引配置失败: " + e.getMessage()); } } }
|
5. 索引性能优化
5.1 索引优化策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
@Component public class IndexOptimizationService { @Autowired private MongoTemplate mongoTemplate;
public List<IndexRecommendation> analyzeAndRecommendIndexes(String collectionName, List<Query> queries) { List<IndexRecommendation> recommendations = new ArrayList<>(); try { for (Query query : queries) { Map<String, Object> performance = analyzeQueryPerformance(collectionName, query); IndexRecommendation recommendation = generateIndexRecommendation(query, performance); if (recommendation != null) { recommendations.add(recommendation); } } System.out.println("生成了 " + recommendations.size() + " 个索引推荐"); return recommendations; } catch (Exception e) { System.err.println("分析查询模式失败: " + e.getMessage()); return new ArrayList<>(); } }
private Map<String, Object> analyzeQueryPerformance(String collectionName, Query query) { try { Document explainResult = mongoTemplate.getCollection(collectionName) .find(query.getQueryObject()) .explain(); Map<String, Object> performance = new HashMap<>(); performance.put("executionTimeMillis", explainResult.get("executionTimeMillis")); performance.put("totalDocsExamined", explainResult.get("totalDocsExamined")); performance.put("totalKeysExamined", explainResult.get("totalKeysExamined")); performance.put("stage", explainResult.get("stage")); return performance; } catch (Exception e) { System.err.println("分析查询性能失败: " + e.getMessage()); return new HashMap<>(); } }
private IndexRecommendation generateIndexRecommendation(Query query, Map<String, Object> performance) { try { Long executionTime = (Long) performance.get("executionTimeMillis"); Long docsExamined = (Long) performance.get("totalDocsExamined"); if (executionTime > 100 || docsExamined > 1000) { IndexRecommendation recommendation = new IndexRecommendation(); recommendation.setQuery(query); recommendation.setExecutionTime(executionTime); recommendation.setDocsExamined(docsExamined); recommendation.setRecommendedIndex(generateIndexFromQuery(query)); return recommendation; } return null; } catch (Exception e) { System.err.println("生成索引推荐失败: " + e.getMessage()); return null; } }
private Index generateIndexFromQuery(Query query) { try { Index index = new Index(); Document queryObject = query.getQueryObject(); for (String field : queryObject.keySet()) { if (!field.startsWith("$")) { index.on(field, Sort.Direction.ASC); } } if (query.getSortObject() != null) { Document sortObject = query.getSortObject(); for (String field : sortObject.keySet()) { Sort.Direction direction = sortObject.getInteger(field) > 0 ? Sort.Direction.ASC : Sort.Direction.DESC; index.on(field, direction); } } return index; } catch (Exception e) { System.err.println("从查询生成索引失败: " + e.getMessage()); return null; } }
public static class IndexRecommendation { private Query query; private Long executionTime; private Long docsExamined; private Index recommendedIndex; public Query getQuery() { return query; } public void setQuery(Query query) { this.query = query; } public Long getExecutionTime() { return executionTime; } public void setExecutionTime(Long executionTime) { this.executionTime = executionTime; } public Long getDocsExamined() { return docsExamined; } public void setDocsExamined(Long docsExamined) { this.docsExamined = docsExamined; } public Index getRecommendedIndex() { return recommendedIndex; } public void setRecommendedIndex(Index recommendedIndex) { this.recommendedIndex = recommendedIndex; } } }
|
5.2 索引监控和告警
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
@Component public class IndexMonitoringService { @Autowired private MongoTemplate mongoTemplate; @Autowired private LogManager logManager;
@Scheduled(fixedRate = 300000) public void monitorIndexPerformance(String collectionName) { try { Map<String, Object> indexStats = getIndexStats(collectionName); Long totalIndexSize = (Long) indexStats.get("totalIndexSize"); if (totalIndexSize > 1024 * 1024 * 1024) { logManager.warning("集合 " + collectionName + " 的索引大小超过1GB: " + totalIndexSize); } List<Document> slowQueries = findSlowQueries(collectionName, 1000); if (!slowQueries.isEmpty()) { logManager.warning("发现 " + slowQueries.size() + " 个慢查询"); } System.out.println("索引性能监控完成"); } catch (Exception e) { logManager.error("索引性能监控失败", e); } }
private Map<String, Object> getIndexStats(String collectionName) { try { Document command = new Document("collStats", collectionName); Document result = mongoTemplate.getDb().runCommand(command); Map<String, Object> indexStats = new HashMap<>(); if (result.containsKey("indexSizes")) { indexStats.put("indexSizes", result.get("indexSizes")); } if (result.containsKey("totalIndexSize")) { indexStats.put("totalIndexSize", result.get("totalIndexSize")); } return indexStats; } catch (Exception e) { System.err.println("获取索引统计信息失败: " + e.getMessage()); return new HashMap<>(); } }
private List<Document> findSlowQueries(String collectionName, long threshold) { try { Query query = new Query(); query.addCriteria(Criteria.where("executionTimeMillis").gt(threshold)); return mongoTemplate.find(query, Document.class, collectionName); } catch (Exception e) { System.err.println("检查慢查询失败: " + e.getMessage()); return new ArrayList<>(); } } }
|
6. 总结
6.1 索引最佳实践
- 合理选择索引类型: 根据查询模式选择合适的索引类型
- 优化复合索引: 将最常用的查询字段放在复合索引的前面
- 避免过度索引: 不要创建不必要的索引,会影响写入性能
- 定期监控: 监控索引使用情况和性能
- 及时清理: 删除不再使用的索引
6.2 性能优化建议
- 单字段索引: 适用于简单的等值查询和范围查询
- 复合索引: 适用于多字段查询,注意字段顺序
- 文本索引: 适用于全文搜索场景
- 地理空间索引: 适用于地理位置查询
- 稀疏索引: 适用于可选字段的索引
6.3 常见问题解决
- 索引未生效: 检查查询条件是否匹配索引
- 索引过大: 考虑使用部分索引或稀疏索引
- 写入性能下降: 减少不必要的索引
- 内存使用过高: 优化索引大小和数量
通过本文的MongoDB索引Java实战指南,您可以掌握MongoDB索引的各种类型、创建方法、性能优化技巧以及在实际项目中的应用。记住,合理使用索引是提升MongoDB性能的关键!