第15章 - 性能优化与最佳实践

第15章 - 性能优化与最佳实践

15.1 性能优化概述

15.1.1 性能瓶颈

┌─────────────────────────────────────────────────────────────────────┐
│                      常见性能瓶颈                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   数据访问                       内存管理                            │
│   ├── 数据源连接                 ├── 几何对象创建                    │
│   ├── 要素迭代                   ├── 大集合处理                      │
│   └── 属性读取                   └── 资源泄漏                        │
│                                                                     │
│   空间计算                       渲染                                │
│   ├── 几何操作                   ├── 样式解析                        │
│   ├── 坐标转换                   ├── 图片生成                        │
│   └── 空间索引                   └── 文本渲染                        │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

15.2 数据访问优化

15.2.1 使用查询优化

public class QueryOptimization {
    
    // 只获取需要的属性
    public static void propertySelection(SimpleFeatureSource source) throws Exception {
        Query query = new Query(source.getSchema().getTypeName());
        
        // 不好:获取所有属性
        // SimpleFeatureCollection all = source.getFeatures();
        
        // 好:只获取需要的属性
        query.setPropertyNames("name", "population");
        SimpleFeatureCollection selected = source.getFeatures(query);
    }
    
    // 使用分页
    public static void paginatedQuery(SimpleFeatureSource source, 
            int pageSize) throws Exception {
        
        int total = source.getCount(Query.ALL);
        
        for (int offset = 0; offset < total; offset += pageSize) {
            Query query = new Query(source.getSchema().getTypeName());
            query.setStartIndex(offset);
            query.setMaxFeatures(pageSize);
            
            SimpleFeatureCollection page = source.getFeatures(query);
            processPage(page);
        }
    }
    
    // 使用空间过滤器缩小范围
    public static void spatialFilter(SimpleFeatureSource source,
            Envelope bounds) throws Exception {
        
        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
        
        Filter bboxFilter = ff.bbox(
            ff.property("the_geom"),
            bounds.getMinX(), bounds.getMinY(),
            bounds.getMaxX(), bounds.getMaxY(),
            "EPSG:4326"
        );
        
        Query query = new Query(source.getSchema().getTypeName(), bboxFilter);
        SimpleFeatureCollection filtered = source.getFeatures(query);
    }
    
    private static void processPage(SimpleFeatureCollection page) {
        // 处理分页数据
    }
}

15.2.2 连接池配置

public class ConnectionPoolConfig {
    
    public static DataStore createOptimizedPostGIS() throws Exception {
        Map<String, Object> params = new HashMap<>();
        
        // 基本连接
        params.put("dbtype", "postgis");
        params.put("host", "localhost");
        params.put("port", 5432);
        params.put("database", "gisdb");
        params.put("user", "postgres");
        params.put("passwd", "password");
        
        // 连接池优化
        params.put("max connections", 20);     // 根据并发量调整
        params.put("min connections", 5);      // 保持最小连接
        params.put("connection timeout", 10);  // 减少等待时间
        params.put("validate connections", true);
        params.put("Test while idle", true);
        
        // 查询优化
        params.put("fetch size", 1000);        // 批量获取
        params.put("Loose bbox", true);        // 宽松边界框
        params.put("preparedStatements", true);// 预编译语句
        params.put("encode functions", true);  // SQL 函数下推
        
        return DataStoreFinder.getDataStore(params);
    }
}

15.3 内存管理

15.3.1 资源释放

public class ResourceManagement {
    
    // 正确的资源释放模式
    public static void correctResourceHandling(File file) throws Exception {
        FileDataStore store = FileDataStoreFinder.getDataStore(file);
        
        try {
            SimpleFeatureSource source = store.getFeatureSource();
            SimpleFeatureCollection fc = source.getFeatures();
            
            // 使用 try-with-resources 自动关闭迭代器
            try (SimpleFeatureIterator iter = fc.features()) {
                while (iter.hasNext()) {
                    SimpleFeature feature = iter.next();
                    // 处理要素
                }
            }  // 自动关闭
            
        } finally {
            store.dispose();  // 确保释放数据源
        }
    }
    
    // 使用 FeatureVisitor 避免手动管理迭代器
    public static void useVisitor(SimpleFeatureCollection fc) throws Exception {
        fc.accepts(new FeatureVisitor() {
            @Override
            public void visit(Feature feature) {
                // 处理要素
            }
        }, null);
    }
}

15.3.2 大数据处理

public class LargeDataHandling {
    
    // 流式处理
    public static void streamProcessing(SimpleFeatureSource source,
            FeatureProcessor processor) throws Exception {
        
        int pageSize = 1000;
        int offset = 0;
        boolean hasMore = true;
        
        while (hasMore) {
            Query query = new Query(source.getSchema().getTypeName());
            query.setStartIndex(offset);
            query.setMaxFeatures(pageSize);
            
            SimpleFeatureCollection batch = source.getFeatures(query);
            int count = 0;
            
            try (SimpleFeatureIterator iter = batch.features()) {
                while (iter.hasNext()) {
                    processor.process(iter.next());
                    count++;
                }
            }
            
            hasMore = count == pageSize;
            offset += count;
            
            // 可选:显式触发 GC
            // System.gc();
        }
    }
    
    public interface FeatureProcessor {
        void process(SimpleFeature feature);
    }
}

15.4 空间索引优化

15.4.1 选择合适的索引

public class SpatialIndexOptimization {
    
    // 构建 STRtree(适合静态数据)
    public static STRtree buildSTRtree(SimpleFeatureCollection fc) throws Exception {
        STRtree index = new STRtree();
        
        try (SimpleFeatureIterator iter = fc.features()) {
            while (iter.hasNext()) {
                SimpleFeature feature = iter.next();
                Geometry geom = (Geometry) feature.getDefaultGeometry();
                index.insert(geom.getEnvelopeInternal(), feature);
            }
        }
        
        index.build();  // 必须调用
        return index;
    }
    
    // 构建 Quadtree(适合动态数据)
    public static Quadtree buildQuadtree(SimpleFeatureCollection fc) throws Exception {
        Quadtree index = new Quadtree();
        
        try (SimpleFeatureIterator iter = fc.features()) {
            while (iter.hasNext()) {
                SimpleFeature feature = iter.next();
                Geometry geom = (Geometry) feature.getDefaultGeometry();
                index.insert(geom.getEnvelopeInternal(), feature);
            }
        }
        
        return index;
    }
    
    // 使用索引查询
    public static List<SimpleFeature> queryWithIndex(STRtree index, 
            Geometry queryGeom) {
        
        List<?> candidates = index.query(queryGeom.getEnvelopeInternal());
        
        List<SimpleFeature> result = new ArrayList<>();
        for (Object obj : candidates) {
            SimpleFeature feature = (SimpleFeature) obj;
            Geometry geom = (Geometry) feature.getDefaultGeometry();
            
            // 精确检查
            if (queryGeom.intersects(geom)) {
                result.add(feature);
            }
        }
        
        return result;
    }
}

15.5 渲染优化

15.5.1 渲染参数调优

public class RenderingOptimization {
    
    public static StreamingRenderer createOptimizedRenderer() {
        StreamingRenderer renderer = new StreamingRenderer();
        
        Map<Object, Object> hints = new HashMap<>();
        
        // 优化选项
        hints.put(StreamingRenderer.OPTIMIZE_FTS_RENDERING_KEY, Boolean.TRUE);
        hints.put(StreamingRenderer.SCALE_COMPUTATION_METHOD_KEY,
            StreamingRenderer.SCALE_ACCURATE);
        hints.put(StreamingRenderer.LINE_WIDTH_OPTIMIZATION_KEY, Boolean.TRUE);
        hints.put(StreamingRenderer.LABEL_CACHE_KEY, new LabelCacheImpl());
        
        // 缓冲区
        hints.put(StreamingRenderer.RENDERING_BUFFER, 50);
        
        renderer.setRendererHints(hints);
        
        // Java2D 优化
        RenderingHints java2dHints = new RenderingHints(null);
        java2dHints.put(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_OFF);  // 关闭抗锯齿提高速度
        java2dHints.put(RenderingHints.KEY_RENDERING,
            RenderingHints.VALUE_RENDER_SPEED);
        
        renderer.setJava2DHints(java2dHints);
        
        return renderer;
    }
}

15.5.2 按比例尺控制

public class ScaleBasedRendering {
    
    public static Style createScaleDependentStyle() {
        StyleFactory sf = CommonFactoryFinder.getStyleFactory();
        FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
        
        // 小比例尺(远视)- 简化符号
        Rule smallScaleRule = sf.createRule();
        smallScaleRule.setMinScaleDenominator(100000);
        smallScaleRule.symbolizers().add(createSimpleSymbol());
        
        // 大比例尺(近视)- 详细符号
        Rule largeScaleRule = sf.createRule();
        largeScaleRule.setMaxScaleDenominator(100000);
        largeScaleRule.symbolizers().add(createDetailedSymbol());
        
        FeatureTypeStyle fts = sf.createFeatureTypeStyle();
        fts.rules().add(smallScaleRule);
        fts.rules().add(largeScaleRule);
        
        Style style = sf.createStyle();
        style.featureTypeStyles().add(fts);
        
        return style;
    }
    
    private static Symbolizer createSimpleSymbol() {
        // 创建简化符号
        return SLD.createPointSymbolizer("circle", Color.RED, 4);
    }
    
    private static Symbolizer createDetailedSymbol() {
        // 创建详细符号
        return SLD.createPointSymbolizer("circle", Color.RED, Color.BLACK, 0.5f, 10);
    }
}

15.6 最佳实践

15.6.1 代码模式

public class BestPractices {
    
    // 1. 始终关闭资源
    public void properResourceHandling(DataStore store) {
        try {
            // 使用 store
        } finally {
            store.dispose();
        }
    }
    
    // 2. 使用批量操作
    public void batchOperations(SimpleFeatureStore store,
            List<SimpleFeature> features) throws Exception {
        
        Transaction transaction = new DefaultTransaction("batch");
        store.setTransaction(transaction);
        
        try {
            int batchSize = 1000;
            for (int i = 0; i < features.size(); i += batchSize) {
                int end = Math.min(i + batchSize, features.size());
                List<SimpleFeature> batch = features.subList(i, end);
                
                DefaultFeatureCollection fc = new DefaultFeatureCollection();
                fc.addAll(batch);
                store.addFeatures(fc);
                
                transaction.commit();
            }
        } catch (Exception e) {
            transaction.rollback();
            throw e;
        } finally {
            transaction.close();
        }
    }
    
    // 3. 重用工厂实例
    private static final GeometryFactory GEOMETRY_FACTORY = 
        JTSFactoryFinder.getGeometryFactory();
    private static final FilterFactory2 FILTER_FACTORY = 
        CommonFactoryFinder.getFilterFactory2();
    private static final StyleFactory STYLE_FACTORY = 
        CommonFactoryFinder.getStyleFactory();
    
    // 4. 缓存常用对象
    private static final Map<String, CoordinateReferenceSystem> CRS_CACHE = 
        new ConcurrentHashMap<>();
    
    public CoordinateReferenceSystem getCRS(String code) throws Exception {
        return CRS_CACHE.computeIfAbsent(code, k -> {
            try {
                return CRS.decode(k);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
    }
}

15.6.2 性能监控

public class PerformanceMonitoring {
    
    public static void timeOperation(String name, Runnable operation) {
        long start = System.currentTimeMillis();
        operation.run();
        long end = System.currentTimeMillis();
        
        System.out.printf("%s: %d ms%n", name, end - start);
    }
    
    public static void memoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        
        long total = runtime.totalMemory();
        long free = runtime.freeMemory();
        long used = total - free;
        long max = runtime.maxMemory();
        
        System.out.printf("内存使用: %d MB / %d MB (最大 %d MB)%n",
            used / 1024 / 1024,
            total / 1024 / 1024,
            max / 1024 / 1024);
    }
}

15.7 本章小结

本章详细介绍了 GeoTools 的性能优化和最佳实践:

  1. 数据访问优化

    • 属性投影
    • 分页查询
    • 连接池配置
  2. 内存管理

    • 资源释放
    • 流式处理
  3. 空间索引

    • STRtree vs Quadtree
    • 索引使用
  4. 渲染优化

    • 渲染参数
    • 比例尺控制
  5. 最佳实践

    • 代码模式
    • 性能监控

关键要点

  • 始终正确关闭资源
  • 使用空间索引提高查询效率
  • 批量操作减少事务开销
  • 重用工厂实例
  • 按比例尺调整渲染复杂度

← 上一章:空间分析与处理 | 返回目录 | 下一章:GeoServer集成开发 →

posted @ 2025-12-29 11:40  我才是银古  阅读(4)  评论(0)    收藏  举报