znlgis 博客

GIS开发与技术分享

第十九章 性能优化与最佳实践

19.1 性能优化概述

19.1.1 性能瓶颈来源

来源 表现 优化方向
数据量 大文件加载慢 数据简化、索引
渲染 地图绘制卡顿 简化符号、缓存
内存 程序崩溃 优化数据结构
IO 读写慢 SSD、缓存
网络 Web服务响应慢 缓存、代理

19.2 数据优化

19.2.1 空间索引

创建空间索引

# Shapefile
processing.run("native:createspatialindex", {'INPUT': layer})

# PostGIS
# CREATE INDEX idx_geom ON table USING GIST(geom);

# SpatiaLite
# SELECT CreateSpatialIndex('table', 'geometry');

19.2.2 几何简化

# 简化几何
result = processing.run("native:simplifygeometries", {
    'INPUT': layer,
    'METHOD': 0,  # Douglas-Peucker
    'TOLERANCE': 10,
    'OUTPUT': 'memory:'
})

19.2.3 数据分块

# 按网格分割大数据集
result = processing.run("native:creategrid", {
    'TYPE': 2,  # Rectangle
    'EXTENT': layer.extent(),
    'HSPACING': 10000,
    'VSPACING': 10000,
    'OUTPUT': 'memory:'
})

# 按网格裁剪
for grid_feature in grid_layer.getFeatures():
    result = processing.run("native:clip", {
        'INPUT': layer,
        'OVERLAY': grid_feature.geometry(),
        'OUTPUT': f'/output/tile_{grid_feature.id()}.gpkg'
    })

19.2.4 使用高效格式

推荐格式

  • GeoPackage(比Shapefile高效)
  • FlatGeobuf(流式处理)
  • Cloud Optimized GeoTIFF(栅格)
  • 空间数据库(大量数据)
# 转换为GeoPackage
processing.run("native:package", {
    'LAYERS': [layer1, layer2],
    'OUTPUT': '/output/data.gpkg',
    'OVERWRITE': True
})

19.3 渲染优化

19.3.1 简化比例尺

设置 > 选项 > 渲染
简化阈值: 1.0
按比例简化

19.3.2 图层比例尺依赖

# 设置图层可见比例尺
layer.setMinimumScale(1000000)  # 最小比例尺
layer.setMaximumScale(1000)     # 最大比例尺
layer.setScaleBasedVisibility(True)

19.3.3 使用缓存

设置 > 选项 > 渲染
渲染缓存: 启用

19.3.4 金字塔/概览图

栅格金字塔

图层属性 > 金字塔 > 构建金字塔

矢量简化图层: 为不同比例尺准备不同详细程度的图层。

19.3.5 符号优化

避免复杂符号

  • 减少符号图层数
  • 避免复杂图案填充
  • 使用简单形状
# 简单符号比复杂符号渲染快
simple = QgsMarkerSymbol.createSimple({'name': 'circle', 'size': '3'})
# 比多层叠加符号快很多

19.4 内存管理

19.4.1 及时释放资源

# 删除不需要的图层
QgsProject.instance().removeMapLayer(layer.id())

# 显式清理
del layer

# 强制垃圾回收
import gc
gc.collect()

19.4.2 使用迭代器

# 好的做法:使用迭代器
for feature in layer.getFeatures():
    # 处理feature
    pass

# 避免:一次性加载所有要素到列表
# features = list(layer.getFeatures())  # 大数据集会消耗大量内存

19.4.3 限制请求

# 只获取需要的字段
request = QgsFeatureRequest()
request.setSubsetOfAttributes(['id', 'name'], layer.fields())

# 限制几何
request.setFlags(QgsFeatureRequest.NoGeometry)

# 限制数量
request.setLimit(1000)

# 空间过滤
request.setFilterRect(extent)

19.4.4 分批处理

# 分批处理大数据
batch_size = 1000
features = layer.getFeatures()

batch = []
for feature in features:
    batch.append(feature)
    
    if len(batch) >= batch_size:
        process_batch(batch)
        batch = []

# 处理剩余
if batch:
    process_batch(batch)

19.5 Processing优化

19.5.1 使用临时输出

# 使用内存输出(小数据)
result = processing.run("native:buffer", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})

# 使用临时文件(大数据)
result = processing.run("native:buffer", {
    'INPUT': layer,
    'OUTPUT': QgsProcessingContext().tempFilePath('.gpkg')
})

19.5.2 禁用不需要的输出

# 只获取需要的输出
result = processing.run("native:buffer", {
    'INPUT': layer,
    'OUTPUT': 'memory:'
})
# 只使用result['OUTPUT']

19.5.3 并行执行

from concurrent.futures import ProcessPoolExecutor

def run_analysis(params):
    return processing.run("native:buffer", params)

# 并行执行多个分析
with ProcessPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(run_analysis, param_list))

19.6 数据库优化

19.6.1 查询优化

-- 使用空间索引
SELECT * FROM table
WHERE ST_Intersects(geom, ST_MakeEnvelope(100, 30, 120, 45, 4326))

-- 避免全表扫描
-- 使用 LIMIT
-- 只选择需要的列
SELECT id, name FROM table LIMIT 1000

19.6.2 连接池

# QGIS自动管理数据库连接
# 对于自定义应用,使用连接池
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool

engine = create_engine(
    'postgresql://user:pass@host/db',
    poolclass=QueuePool,
    pool_size=5,
    max_overflow=10
)

19.6.3 服务端处理

-- 在数据库端完成计算
SELECT 
    region_name,
    COUNT(*) as point_count,
    SUM(population) as total_pop
FROM points p
JOIN regions r ON ST_Within(p.geom, r.geom)
GROUP BY region_name

19.7 网络优化

19.7.1 启用缓存

设置 > 选项 > 网络 > 缓存
目录: /path/to/cache
大小: 500 MB

19.7.2 代理设置

设置 > 选项 > 网络 > 代理
启用代理加速访问

19.7.3 本地瓦片缓存

# 使用本地瓦片缓存
# 配置XYZ瓦片源时使用本地缓存服务

19.8 项目优化

19.8.1 项目设置

项目 > 属性 > 通用
- 评估默认值: 仅在需要时
- 自动事务分组: 按需启用

19.8.2 减少图层数量

  • 合并相似图层
  • 使用规则渲染代替多图层
  • 移除不需要的图层

19.8.3 优化启动

设置 > 选项 > 通用
- 检查QGIS版本: 禁用
- 加载插件: 只加载必要的

19.9 最佳实践

19.9.1 数据管理

实践 说明
使用GeoPackage 比Shapefile更高效
创建空间索引 加速空间查询
数据分层 按比例尺使用不同详细程度
定期清理 删除临时文件和缓存

19.9.2 项目管理

实践 说明
相对路径 便于项目迁移
模板使用 标准化项目设置
版本控制 跟踪项目变更
文档记录 记录数据源和处理步骤

19.9.3 代码实践

# 使用上下文管理器
with edit(layer):
    layer.addFeature(feature)

# 批量操作
layer.startEditing()
layer.dataProvider().addFeatures(features)
layer.commitChanges()

# 错误处理
try:
    result = processing.run(...)
except QgsProcessingException as e:
    print(f"处理错误: {e}")

19.9.4 工作流程

  1. 数据准备:清洗、转换、索引
  2. 测试小样本:在小数据集上测试
  3. 监控性能:观察内存和CPU使用
  4. 渐进处理:分批处理大数据
  5. 结果验证:检查输出正确性

19.10 性能监控

19.10.1 日志分析

视图 > 面板 > 日志消息

19.10.2 渲染时间

# 获取渲染时间
canvas = iface.mapCanvas()
canvas.renderStarting.connect(lambda: print("开始渲染"))
canvas.renderComplete.connect(lambda: print("渲染完成"))

19.10.3 内存使用

import psutil

# 监控内存使用
process = psutil.Process()
print(f"内存使用: {process.memory_info().rss / 1024 / 1024:.2f} MB")

19.11 小结

本章介绍了QGIS性能优化方法:

关键要点

  1. 使用空间索引加速查询
  2. 简化几何和符号减少渲染负担
  3. 合理管理内存和资源
  4. 优化数据库查询
  5. 使用缓存提高网络性能
  6. 遵循最佳实践

性能优化是高效使用QGIS的关键。


上一章第18章 高级功能与扩展

下一章第20章 实战案例与项目应用


← 上一章 目录 下一章 →