第 3 章。PostGIS 管理

目录

3.1. 性能调优

PostGIS 性能调优与 PostgreSQL 工作负载的调优非常相似。唯一的额外考虑因素是几何图形和栅格通常很大,因此与 PostgreSQL 的其他类型的查询相比,与内存相关的优化通常对 PostGIS 的影响更大。

有关优化 PostgreSQL 的一般详细信息,请参阅 调优您的 PostgreSQL 服务器

对于 PostgreSQL 9.4+,可以通过使用 ALTER SYSTEM 命令在服务器级别设置配置,而无需触及 postgresql.confpostgresql.auto.conf

ALTER SYSTEM SET work_mem = '256MB';
-- this forces non-startup configs to take effect for new connections
SELECT pg_reload_conf();
-- show current setting value
-- use SHOW ALL to see all settings
SHOW work_mem;

除了 Postgres 设置外,PostGIS 还有一些自定义设置,这些设置列在 第 7.22 节,“Grand Unified Custom Variables (GUCs)”中。

3.1.1. 启动

这些设置在 postgresql.conf 中配置

constraint_exclusion

  • 默认值:partition

  • 这通常用于表分区。此设置的默认值设置为“partition”,这对于 PostgreSQL 8.4 及更高版本来说是理想的,因为它将强制规划器仅分析继承层次结构中的表以进行约束考虑,否则不会支付规划器的代价。

shared_buffers

  • 默认值:在 PostgreSQL 9.6 中约为 128MB

  • 设置为可用 RAM 的大约 25% 到 40%。在 Windows 上,您可能无法设置得那么高。

max_worker_processes 此设置仅适用于 PostgreSQL 9.4+。对于 PostgreSQL 9.6+,此设置具有额外的意义,因为它控制您可以用于并行查询的最大进程数。

  • 默认值:8

  • 设置系统可以支持的最大后台进程数。此参数只能在服务器启动时设置。

3.1.2. 运行时

work_mem - 设置用于排序操作和复杂查询的内存大小

  • 默认值:1-4MB

  • 对于大型数据库、复杂查询、大量 RAM,请向上调整

  • 对于许多并发用户或低 RAM,请向下调整。

  • 如果您有大量 RAM 和少量开发人员

    SET work_mem TO '256MB';

maintenance_work_mem - 用于 VACUUM、CREATE INDEX 等的内存大小。

  • 默认值:16-64MB

  • 通常太低 - 在交换内存时占用 I/O,锁定对象

  • 建议在具有大量 RAM 的生产服务器上使用 32MB 到 1GB,但这取决于并发用户的数量。如果您有大量 RAM 和少量开发人员

    SET maintenance_work_mem TO '1GB';

max_parallel_workers_per_gather

此设置仅适用于 PostgreSQL 9.6+,并且只会影响 PostGIS 2.3+,因为只有 PostGIS 2.3+ 支持并行查询。如果设置为大于 0,则某些查询(例如涉及 ST_Intersects 等关系函数的查询)可以使用多个进程,并且在执行此操作时可以运行速度提高两倍以上。如果您有很多处理器可以空闲,则应将此值更改为您拥有的处理器数量。还要确保将 max_worker_processes 增加到至少与此数字一样高。

  • 默认值:0

  • 设置单个 Gather 节点可以启动的最大工作进程数。并行工作进程是从 max_worker_processes 建立的进程池中获取的。请注意,请求的工作进程数可能在运行时不可用。如果发生这种情况,计划将以比预期更少的工作进程运行,这可能效率低下。将此值设置为 0(默认值)将禁用并行查询执行。

3.2. 配置栅格支持

如果您启用了栅格支持,您可能需要阅读以下内容,了解如何正确配置它。

从 PostGIS 2.1.3 开始,默认情况下禁用数据库外栅格和所有栅格驱动程序。为了重新启用这些,您需要在服务器环境中设置以下环境变量 POSTGIS_GDAL_ENABLED_DRIVERSPOSTGIS_ENABLE_OUTDB_RASTERS。对于 PostGIS 2.2,您可以使用更跨平台的方法来设置相应的 第 7.22 节,“Grand Unified Custom Variables (GUCs)”

如果要启用脱机栅格

POSTGIS_ENABLE_OUTDB_RASTERS=1

任何其他设置或根本不设置都将禁用数据库外栅格。

为了启用 GDAL 安装中提供的所有 GDAL 驱动程序,请按如下方式设置此环境变量

POSTGIS_GDAL_ENABLED_DRIVERS=ENABLE_ALL

如果您只想启用特定的驱动程序,请按如下方式设置环境变量

POSTGIS_GDAL_ENABLED_DRIVERS="GTiff PNG JPEG GIF XYZ"
[Note]

如果您在 Windows 上,请不要引用驱动程序列表

设置环境变量因操作系统而异。对于通过 apt-postgresql 安装在 Ubuntu 或 Debian 上的 PostgreSQL,首选方法是编辑 /etc/postgresql/10/main/environment,其中 10 指的是 PostgreSQL 的版本,main 指的是集群。

在 Windows 上,如果您作为服务运行,您可以通过系统变量进行设置,对于 Windows 7,您可以通过右键单击计算机->属性高级系统设置或在资源管理器中导航到 控制面板\所有控制面板项\系统 来访问它。然后单击 高级系统设置->高级->环境变量 并添加新的系统变量。

设置环境变量后,您需要重新启动 PostgreSQL 服务,以使更改生效。

3.3. 创建空间数据库

3.3.1. 使用 EXTENSION 以空间方式启用数据库

如果您使用的是 PostgreSQL 9.1+ 并且已编译并安装了 extensions/postgis 模块,则可以使用 EXTENSION 机制将数据库转换为空间数据库。

核心 postgis 扩展包括几何图形、地理、spatial_ref_sys 以及所有函数和注释。栅格和拓扑打包为单独的扩展。

在您要以空间方式启用的数据库中运行以下 SQL 代码片段

      CREATE EXTENSION IF NOT EXISTS plpgsql;
      CREATE EXTENSION postgis;
      CREATE EXTENSION postgis_raster; -- OPTIONAL
      CREATE EXTENSION postgis_topology; -- OPTIONAL

3.3.2. 不使用 EXTENSION 以空间方式启用数据库(不推荐)

[Note]

如果您不能或不想在 PostgreSQL 扩展目录中安装 PostGIS(例如在测试、开发或受限制的环境中),通常才需要这样做。

通过加载 [prefix]/share/contrib 中(在构建阶段指定)的各种 sql 文件,将 PostGIS 对象和函数定义添加到您的数据库中。

核心 PostGIS 对象(几何图形和地理类型及其支持函数)位于 postgis.sql 脚本中。栅格对象位于 rtpostgis.sql 脚本中。拓扑对象位于 topology.sql 脚本中。

对于完整的 EPSG 坐标系定义标识符集,您还可以加载 spatial_ref_sys.sql 定义文件并填充 spatial_ref_sys 表。这将允许您对几何图形执行 ST_Transform() 操作。

如果您希望向 PostGIS 函数添加注释,您可以在 postgis_comments.sql 脚本中找到它们。只需从 psql 终端窗口键入 \dd [function_name] 即可查看注释。

在终端中运行以下 Shell 命令

    DB=[yourdatabase]
    SCRIPTSDIR=`pg_config --sharedir`/contrib/postgis-3.4/

    # Core objects
    psql -d ${DB} -f ${SCRIPTSDIR}/postgis.sql
    psql -d ${DB} -f ${SCRIPTSDIR}/spatial_ref_sys.sql
    psql -d ${DB} -f ${SCRIPTSDIR}/postgis_comments.sql # OPTIONAL

    # Raster support (OPTIONAL)
    psql -d ${DB} -f ${SCRIPTSDIR}/rtpostgis.sql
    psql -d ${DB} -f ${SCRIPTSDIR}/raster_comments.sql # OPTIONAL

    # Topology support (OPTIONAL)
    psql -d ${DB} -f ${SCRIPTSDIR}/topology.sql
    psql -d ${DB} -f ${SCRIPTSDIR}/topology_comments.sql # OPTIONAL

3.4. 升级空间数据库

升级现有的空间数据库可能很棘手,因为它需要替换或引入新的 PostGIS 对象定义。

不幸的是,并非所有定义都可以在活动数据库中轻松替换,因此有时最好的选择是转储/重新加载过程。

PostGIS 为次要或错误修复版本提供了软升级程序,为主要版本提供了硬升级程序。

在尝试升级 PostGIS 之前,始终值得备份您的数据。如果您使用 pg_dump 的 -Fc 标志,您将始终能够使用硬升级来恢复转储。

3.4.1. 软升级

如果您使用扩展安装了数据库,则还需要使用扩展模型进行升级。如果您使用旧的 sql 脚本方式安装,则建议您将安装切换到扩展,因为不再支持脚本方式。

3.4.1.1. 使用扩展的 9.1+ 软升级

如果您最初使用扩展安装了 PostGIS,那么您也需要使用扩展进行升级。使用扩展进行次要升级是相当轻松的。

如果您运行的是 PostGIS 3 或更高版本,则应使用 PostGIS_Extensions_Upgrade 函数升级到您已安装的最新版本。

SELECT postgis_extensions_upgrade();

如果您运行的是 PostGIS 2.5 或更低版本,请执行以下操作

ALTER EXTENSION postgis UPDATE;
SELECT postgis_extensions_upgrade();
-- This second call is needed to rebundle postgis_raster extension
SELECT postgis_extensions_upgrade();

如果您安装了多个版本的 PostGIS,并且不想升级到最新版本,您可以按如下方式显式指定版本

ALTER EXTENSION postgis UPDATE TO "3.5.2dev";
ALTER EXTENSION postgis_topology UPDATE TO "3.5.2dev";

如果您收到如下错误通知

No migration path defined for … to 3.5.2dev

那么您需要备份数据库,如 第 3.3.1 节,“使用 EXTENSION 以空间方式启用数据库” 中所述创建一个新的数据库,然后在此新数据库之上还原备份。

如果您收到如下通知消息

Version "3.5.2dev" of extension "postgis" is already installed

那么一切都已是最新状态,您可以安全地忽略它。除非您尝试从开发版本升级到下一个版本(没有获得新的版本号);在这种情况下,您可以将“next”附加到版本字符串,下次您需要再次删除“next”后缀

ALTER EXTENSION postgis UPDATE TO "3.5.2devnext";
ALTER EXTENSION postgis_topology UPDATE TO "3.5.2devnext";
[Note]

如果您最初安装 PostGIS 时没有指定版本,您通常可以跳过在还原之前重新安装 postgis 扩展,因为备份只具有 CREATE EXTENSION postgis,因此在还原期间会拾取最新的最新版本。

[Note]

如果您要从 3.0.0 之前的版本升级 PostGIS 扩展,您将拥有一个新的扩展 postgis_raster,如果您不需要栅格支持,可以安全地删除它。您可以按如下方式删除

DROP EXTENSION postgis_raster;

3.4.1.2. Pre 9.1+ 或不使用扩展的软升级

本节仅适用于那些不使用扩展安装 PostGIS 的人。如果您有扩展并尝试使用此方法升级,您将收到如下消息

can't drop … because postgis extension depends on it

注意:如果您要从 PostGIS 1.* 移动到 PostGIS 2.* 或从 PostGIS 2.* 移动到 r7409 之前的版本,则不能使用此过程,而是需要执行 硬升级

编译并安装 (make install) 后,您应该在安装文件夹中找到一组 *_upgrade.sql 文件。您可以使用以下命令列出所有文件

ls `pg_config --sharedir`/contrib/postgis-3.5.2dev/*_upgrade.sql

依次加载它们,从 postgis_upgrade.sql 开始。

psql -f postgis_upgrade.sql -d your_spatial_database

相同的过程适用于栅格、拓扑和 sfcgal 扩展,升级文件分别名为 rtpostgis_upgrade.sqltopology_upgrade.sqlsfcgal_upgrade.sql。如果您需要它们

psql -f rtpostgis_upgrade.sql -d your_spatial_database
psql -f topology_upgrade.sql -d your_spatial_database
psql -f sfcgal_upgrade.sql -d your_spatial_database

建议您通过运行以下命令切换到基于扩展的安装

psql -c "SELECT postgis_extensions_upgrade();"
[Note]

如果您找不到专门用于升级您正在使用的版本的 postgis_upgrade.sql,则表示您使用的版本太早,无法进行软升级,并且需要执行 硬升级

PostGIS_Full_Version 函数应通过“procs need upgrade”消息通知您需要运行这种升级。

3.4.2. 硬升级

所谓“硬升级”,指的是对启用 PostGIS 的数据库进行完全的转储/重新加载。当 PostGIS 对象的内部存储发生变化或无法进行软升级时,您需要进行硬升级。请参考发行说明附录,其中会针对每个版本说明是否需要转储/重新加载(硬升级)来进行升级。

转储/重新加载过程由 `postgis_restore` 脚本辅助完成,该脚本负责跳过转储文件中所有属于 PostGIS 的定义(包括旧的定义),允许您将模式和数据恢复到已安装 PostGIS 的数据库中,而不会出现重复符号错误或引入已弃用的对象。

有关 Windows 用户的补充说明,请访问 Windows 硬升级

具体步骤如下:

  1. 创建一个要升级的数据库(我们称之为 olddb)的“自定义格式”转储,包括二进制 blob (-b) 和详细 (-v) 输出。用户可以是数据库的所有者,不需要是 postgres 超级帐户。

    pg_dump -h localhost -p 5432 -U postgres -Fc -b -v -f "/somepath/olddb.backup" olddb
  2. 在新数据库中全新安装 PostGIS,我们将此数据库称为 newdb。有关如何执行此操作的说明,请参阅第 3.3.2 节,“不使用 EXTENSION 空间启用数据库(不推荐)”第 3.3.1 节,“使用 EXTENSION 空间启用数据库”

    您转储中的 `spatial_ref_sys` 条目将会被恢复,但它们不会覆盖 `spatial_ref_sys` 中已存在的条目。这是为了确保官方集合中的修复能够正确地传播到恢复的数据库中。如果出于任何原因您真的想要自定义覆盖标准条目,请在创建新数据库时不要加载 `spatial_ref_sys.sql` 文件。

    如果您的数据库非常旧,或者您知道您在视图和函数中使用了长期弃用的函数,您可能需要加载 legacy.sql 以使所有函数和视图等正常恢复。只有在_真的_需要时才这样做。如果可能,请考虑在转储之前升级您的视图和函数。可以通过加载 uninstall_legacy.sql 来删除已弃用的函数。

  3. 使用 `postgis_restore` 将您的备份恢复到新创建的 newdb 数据库中。如果出现意外错误,psql 会将其打印到标准错误流中。请记录这些错误。

    postgis_restore "/somepath/olddb.backup" | psql -h localhost -p 5432 -U postgres newdb 2> errors.txt

以下情况下可能会出现错误:

  1. 您的一些视图或函数使用了已弃用的 PostGIS 对象。为了解决这个问题,您可以尝试在恢复之前加载 legacy.sql 脚本,或者您必须恢复到仍然包含这些对象的 PostGIS 版本,并在移植代码后再次尝试迁移。如果 legacy.sql 的方法对您有效,请不要忘记修复您的代码以停止使用已弃用的函数,并通过加载 uninstall_legacy.sql 来删除它们。

  2. 转储文件中 `spatial_ref_sys` 的一些自定义记录具有无效的 SRID 值。有效的 SRID 值大于 0 且小于 999000。999000 到 999999 范围内的值保留供内部使用,而大于 999999 的值根本不能使用。所有具有无效 SRID 的自定义记录都将被保留,其中大于 999999 的记录将被移动到保留范围内,但是 `spatial_ref_sys` 表将失去一个检查约束,该约束用于保护该不变性成立,并且可能也会失去其主键(当多个无效的 SRID 被转换为相同的保留 SRID 值时)。

    为了解决这个问题,您应该将您的自定义 SRS 复制到一个具有有效值的 SRID(可能在 910000..910999 范围内),将所有表转换为新的 srid(请参阅 UpdateGeometrySRID),从 `spatial_ref_sys` 中删除无效的条目,并使用以下命令重建检查约束:

    ALTER TABLE spatial_ref_sys ADD CONSTRAINT spatial_ref_sys_srid_check check (srid > 0 AND srid < 999000 );
    
    ALTER TABLE spatial_ref_sys ADD PRIMARY KEY(srid));
        

    如果您正在升级包含法国 IGN 制图的旧数据库,您可能会有超出范围的 SRID,并且在导入数据库时会看到类似这样的问题:

     WARNING: SRID 310642222 converted to 999175 (in reserved zone)

    在这种情况下,您可以尝试以下步骤:首先从 `postgis_restore` 生成的 sql 中完全删除 IGN。因此,在运行

    postgis_restore "/somepath/olddb.backup" > olddb.sql

    运行此命令

    grep -v IGNF olddb.sql > olddb-without-IGN.sql

    然后创建您的 newdb,激活所需的 Postgis 扩展,并使用以下方式正确插入法国系统 IGN:此脚本。完成这些操作后,导入您的数据。

    psql -h localhost -p 5432 -U postgres -d newdb -f olddb-without-IGN.sql  2> errors.txt