首页 / 资讯中心 / 文章详情

PostgreSQL 9.6.10 Windows安装与调试完整指南:从版本对齐到排障实战

PostgreSQL 9.6.10 Windows安装与调试完整指南:从版本对齐到排障实战 ★ FEATURED ARTICLE
我接手过一套还跑在 PostgreSQL 9.6.10 上的老业务系统。线上库里存着好几年的业务数据平时没人敢碰可真要调试问题、做数据修复、验证新逻辑的时候麻烦就来了——你不可能拿生产库做实验。于是本地 Windows 机器上必须搭一个同样版本的 PostgreSQL 9.6.10 开发环境。刚开始我以为装个数据库哪有什么难度结果在 Windows 下真正把它跑顺前前后后踩了不少坑服务起不来、端口被占、pg_hba.conf 写错、中文 locale 捣乱……这篇就围绕 PostgreSQL 9.6.10 在 Windows 下的安装和调试把我从头到尾的做法、判断逻辑和排障顺序完整写一遍适合需要本地复现老版本环境、或者正在被数据库连接问题折磨的开发者参考。1. 为什么还在用 9.6.10别只盯着“旧版本”三个字1.1 9.6.10 的版本坐标很多新手看到 9.6.10 的第一反应是“这不是五六年前的东西了吗”。这种想法没错但“旧”不代表“没有人在用”。9.6 系列从 2016 年开始发布9.6.10 是它生命周期里的一个维护版本在它之后的 10、11、12、13、14、15 甚至 16每代都带来了新特性可现实是大量业务系统还稳定跑在 9.6 上尤其是部署时间比较早、后续一直靠维护续命的老系统。我需要强调一个容易被忽略的点本地开发环境的版本号最好跟生产环境做到大版本和小版本完全一致。大版本决定了 SQL 语法、优化器行为、系统表结构小版本则包含了一堆 bug 修复不同小版本的细微行为差异在特定场景下也足够让人头疼。你如果本地装的是 15线上是 9.6.10查一个执行计划、测一个函数返回结果、验证一个批量导入脚本都可能出现“本地正常、线上异常”的诡异情况。所以这台 Windows 开发机就必须老老实实装 9.6.10。1.2 本地环境与生产环境对齐带来的实际价值做版本对齐不是强迫症而是调试效率问题。我举几个实际场景线上库出现死锁或者慢查询你需要在本地用同版本库复现相同的执行计划才能定位是索引失效还是统计信息问题老应用的某个扩展或者存储过程只兼容 9.6新版本根本不支持要评估升级到新版本之前你得先在一模一样的环境里跑一遍兼容性测试数据修复脚本涉及系统表操作9.6 的系统表结构和 10 以后差异很大照着新版本文档写脚本往往直接废掉。另外要清楚9.6 和 10、11 以后版本有几项关键差异。认证上9.6 默认使用 md5而新版本默认是 scram-sha-2569.6 没有声明式分区没有 identity 列并行查询能力也远不如后面几个版本。这些差别不亲自跑一遍很容易在排查线上问题的过程中产生严重误判。所以结论很简单别管它多老只要线上是它本地就得是它。2. 安装向导逐页拆解每个选项都别默认到底2.1 下载、组件与目录规划先在下载页面找到 Windows x86-64 对应的 9.6.10 安装包。下载后右键选择“以管理员身份运行”这一步在 Windows 10/11 上尤其重要否则后续写注册表、创建 Windows 服务都可能报权限不足。安装向导第一步会让你选安装目录。默认是C:\Program Files\PostgreSQL\9.6我的建议是改到空间充裕的独立分区比如D:\PostgreSQL\9.6。这样做的原因很简单这个目录里装着可执行文件、共享库和一部分配置文件如果哪天 C 盘满了或者系统还原出问题重装系统也不会直接干掉数据库程序本体。更重要的是安装目录和你下面的数据目录一定要分开程序归程序数据归数据。组件选择页面里默认会勾选 PostgreSQL Server、pgAdmin 4、Stack Builder 等。我的做法是PostgreSQL Server 和 Command Line Tools 必选pgAdmin 4 可以留着备用但 Stack Builder 一定去掉。这是个容易忽视的坑——Stack Builder 是给后续装扩展、驱动用的辅助工具早期版本它总在你不需要的时候跳出来提示更新实际用处不大装完还占用一大堆启动项。在纯粹的命令行工作流里它属于可以完全绕开的东西。2.2 数据目录、超级用户密码和端口安装向导中“Data Directory”一页我填的是D:\pgdata\9.6。这里需要特别注意数据目录和安装目录分开带来的好处很直接。数据库实例升级时可以只处理数据目录不必连带程序目录一起纠结做备份时直接拷贝数据目录就能得到一个冷备份以后要装第二个 PostgreSQL 实例数据目录互相独立互不干扰。接下来是超级用户密码。这个密码同时会被安装器用来创建 Windows 下的 postgres 服务账户。也就是说安装完成后你客户端连接数据库要用的 postgres 用户密码就是这一行。建议记到密码管理器里这个密码丢了在 Windows 上重置比 Linux 麻烦得多。端口默认是 5432。如果本机之前装过其他 PostgreSQL 实例或者某进程已经占用 5432安装器在创建服务时不会帮你检查端口是否干净最终表现就是服务启动失败。这块我强烈建议在安装前先执行一条命令看一眼netstat -ano | findstr 5432如果有输出说明端口已占用那就直接安装时改成 5433 或 5434别跟现有进程硬碰。2.3 Locale 选择Windows 中文环境最容易埋雷的地方安装向导里有一页叫 Locale这大概是整个安装过程中最容易被忽略、后果却最严重的选项。默认情况下Windows 安装包会跟随系统区域中文系统通常对应Chinese (Simplified)_China.936。这个值在后续会直接写入数据库的lc_collate和lc_ctype影响排序规则、大小写比较、甚至部分字符串函数的行为。等你建库、导数据、发现中文排序结果跟生产环境完全不一样的时候再想改就晚了——lc_collate和lc_ctype在 initdb 之后基本固化想换只能重建整个数据库集群。我的建议很简单本地开发调试环境Locale 直接选 C。如果你确实需要其他排序行为再考虑English_United States.1252。对大多数老系统兼容性测试来说C是最省事、最不容易出幺蛾子的选择字符集则配合编码设置为 UTF8。有一个概念必须说清楚Locale 和 encoding 是两回事。encoding 决定字符怎么存Locale 决定字符串怎么比较和排序。很多人看到 server_encoding 是 UTF8 就觉得万事大吉却忽略了 lc_collate 是中文 Windows 的默认值这就是后面各种诡异排序问题的根源。2.4 安装过程常见的失败现场安装到“服务创建”这一步挂掉是 Windows 下最常见的事故现场。日志往往只给你一句“服务 postgresql-x64-9.6 未能启动”让人一头雾水。我遇到过的原因大致有这几类第一数据目录残留。如果安装前曾经手动建过D:\pgdata\9.6这个目录里面还有旧文件initdb 初始化新实例时会直接拒绝操作因为没有清空目录。解决方法是把目录先移走改名再让安装器新建一个干净的目录。第二安全软件拦截。安装器要创建 Windows 服务并写入注册表某些安全软件会把这个动作当成恶意行为拦下来。表现为安装过程看起来正常但最后服务创建失败或系统服务列表里根本找不到该项。建议安装前临时关闭实时防护装完再开或者安装后手动把 PostgreSQL 的相关目录加入白名单。第三旧实例残留。如果之前卸载过 PostgreSQL 但没卸干净Windows 服务列表里可能残留一个同名服务此时新安装器不会自动覆盖最终表现就是新装程序无法使用。管理员权限的 cmd 窗口里可以做两件事查服务状态以及确认残留再决定是否手动清理服务项。3. 安装完成后的三件套验证服务、日志、命令行3.1 Windows 服务状态与监听检查安装完成的窗口一关别急着连数据库先按顺序做三步检查。第一步打开“服务”管理窗口找到postgresql-x64-9.6看状态。如果显示“正在运行”那是好事如果是“已停止”右键点启动观察会不会报错。第二步用命令行验证得更准确sc query postgresql-x64-9.6看输出里的STATE那一行如果是RUNNING说明 Windows 服务层面是正常的。注意服务名里 x64 对应 64 位安装包32 位包可能叫postgresql-9.6具体情况以你机器上实际安装为准。第三步确认端口监听netstat -ano | findstr 5432如果你看到类似TCP 0.0.0.0:5432 LISTENING的记录说明 postgres.exe 已经真实监听了端口。这一步特别重要的原因是Windows 服务状态为“运行”不一定等于数据库在正常工作服务进程可能因为初始化失败反复重启也可能因为配置文件错误根本没有绑定端口。服务、进程、监听这三层每一层都要确认。3.2 psql 连接验证在命令行里进入安装目录下的 bin 目录然后执行cd D:\PostgreSQL\9.6\bin psql -U postgres -h 127.0.0.1 -p 5432 -d postgres这里有个细节-h参数指定的是主机地址写localhost和写127.0.0.1在某些系统上会有细微差别——localhost可能解析到 IPv6 的::1如果 PostgreSQL 只监听了 IPv4 就会连接失败。所以在排查阶段我习惯先写127.0.0.1做最小化验证排除掉 DNS 和 IPv6 这一层干扰。输入密码进入 psql 后执行这几条命令作为验货SELECT version(); SHOW server_encoding; SHOW lc_collate; SHOW lc_ctype;看到版本号是 9.6.10server_encoding 是 UTF8lc_collate 和 lc_ctype 是 C那么安装这步基本就是干净的。如果这里的 lc_collate 显示成 Chinese 之类那就要回到 2.3 节准备重建实例了。3.3 日志文件定位与快速解读Windows 事件查看器对 PostgreSQL 的意义有限它只记录“服务启动了/停止了”这种粗粒度信息真正的数据库错误还是在 PostgreSQL 自己的日志里。9.6 在 Windows 下默认启用了日志收集日志在数据目录下的pg_log子目录里文件名长这样postgresql-2025-01-15_103000.log。很多第一次接触的人会到处找日志文件其实就是这一个目录。每当服务启动失败、连接被莫名断开、崩溃重启之后第一个动作应该是打开这个目录下最新的日志文件看最后几十行。常见关键信息包括FATAL: could not create listen socket for localhost说明端口绑定失败Permission denied大概率是数据目录的权限或 ACL 异常database xxx does not exist说明你连接的库名写错了或者还没建库invalid value for parameter说明 postgresql.conf 里的某项参数写得不合法。日志分析能力是整个调试链路里最值钱的一环。建立“出错先看日志”的肌肉记忆能省掉大量瞎猜的时间。4. 调试实录三个高频故障的完整排查链路4.1 服务起不来的排障顺序我在 Windows 上遇到的第一个硬骨头就是服务启动失败。现象是服务管理窗口里点“启动”状态转了几个圈又回到“已停止”偶尔弹一个错误码。这时候不要慌按顺序排查。第一去看最新日志里最后几行。比如下面这种2025-01-15 10:30:01 CST FATAL: could not create listen socket for localhost 2025-01-15 10:30:01 CST HINT: bind() to port 5432 failed: Permission denied这个错误已经说得很明白了端口 5432 被其他东西占了。怎么确认是谁两条命令连起来用netstat -ano | findstr 5432 tasklist | findstr pid如果发现占用的是一个旧的 postgres.exe那大概率是另一套 PostgreSQL 实例还在跑。处理思路就两条停掉旧进程或者在新实例的配置文件里改端口。我更倾向于改端口因为本地这种场景下谁也不想影响其他已经跑着的服务。第二如果日志里没有明确的 FATAL但服务就是起不来检查postmaster.pid文件。这个文件在数据目录下记录着 postmaster 进程的 PID 等信息。如果系统崩溃、电源断电、或者任务管理器强杀了 postgres 进程PID 文件可能残留下来下次启动时 postmaster 检测到“疑似已有实例在运行”会拒绝启动或者卡在初始化阶段。处理这类残留前必须先确认没有真的 postgres 进程在跑tasklist | findstr postgres确认进程列表里完全没有 postgres 之后再手动删除数据目录下的postmaster.pid。注意不要在有进程运行时删否则会破坏运行实例的状态文件。第三数据目录权限问题。Windows 的权限模型和 Linux 不太一样数据目录由安装器创建时ACL 通常是按服务账户来配置的。有时候你从别人那里拷来一个数据目录或者改过目录权限、移动过位置当前服务账户没有访问权限启动就会在初始化阶段失败。日志里多半会出现could not open directory或者Permission denied相关条目。这种情况处理起来比较干脆确认目录里没有必须保留的数据就直接用 initdb 重建一个新数据目录如果有数据要保留那就先解决 ACL 授权给服务运行账户授予数据目录的完全控制权限。4.2 Connection refused 不等于服务没启动“psql: could not connect to server: Connection refused”这句话可能是 PostgreSQL 调试里最劝退人的报错。先要破一个误解它不等于数据库没在运行更多时候是“客户端到服务端的这条链路里有环节没打通”。排查链路应该是先看监听在不在。执行netstat -ano | findstr 5432如果没有 LISTENING 记录说明 postgres 没起来或者端口配得不对回到 4.1 节。如果监听在继续。看服务端绑定地址。执行SHOW listen_addresses;9.6 的默认值是localhost意味着它只监听本地回环地址。这时候你从局域网另一台机器连它或通过机器名访问都会被拒绝。想支持局域网连接需要改配置listen_addresses *改完重启服务。注意这个参数不能靠pg_reload_conf()生效必须重启实例。看 pg_hba.conf 的认证规则。9.6 的 pg_hba.conf 在数据目录下大致的规则格式如下# TYPE DATABASE USER ADDRESS METHOD host all all 127.0.0.1/32 md5 host all all ::1/128 md5 host all all 192.168.1.0/24 md5如果客户端 IP 不在任何一条规则覆盖范围内即使数据库正常运行、端口监听正常照样会被拒绝连接而且错误信息可能就一句话 “no pg_hba.conf entry for host”。很多人在这一步就直接懵了。修改完 pg_hba.conf 之后不需要重启服务执行一次重载即可SELECT pg_reload_conf();或者用命令行方式pg_ctl reload -D D:\pgdata\9.6最后才轮到 Windows 防火墙。默认规则不会放行外部对 5432 端口的访问开发机如果只在本机连这一步跳过也行要通过局域网连用管理员 cmd 放行netsh advfirewall firewall add rule namePostgreSQL 5432 dirin actionallow protocolTCP localport5432这里有一条安全底线要反复强调调试时绝不要为了省事把 pg_hba.conf 里的地址段改成0.0.0.0/0再用trust。开发环境即便只有你自己用trust认证等于裸奔某些数据误操作和恶意访问成本都低到离谱。放行局域网网段、使用 md5 密码认证是底线。4.3 中文 Windows 下的 locale 与编码陷阱和前两个“起不来”“连不上”的问题不同locale 问题带迷惑性因为数据库能正常起来、连接也正常数据甚至能查能导但某些行为就是不对。具体表现有这几种中文排序结果和 Linux 生产库不一致导入导出的中文文本在客户端显示乱码新建数据库时必须反复指定 ENCODING 和 LC_COLLATE否则建库报错字符串比较行为不符合预期比如大小写、空格处理差异。根子都在安装时选的那个 Locale。中文 Windows 默认值对应Chinese (Simplified)_China.936代码页 936 是 GBK 体系和 Linux 上常见的 UTF8/C 组合行为差异很大。验证当前实例的 locale 状态很简单SHOW lc_collate; SHOW lc_ctype;判断标准是这样的如果你想做一个“跟 Linux 生产环境行为一致的本地复现环境”那lc_collate和lc_ctype至少不能走 Windows 代码页路线最省心的是C。如果你发现已经是C那就没问题如果是中文系统默认值而数据目录里还没什么有价值的内容直接重建实例比硬撑着改参数靠谱得多。重建实例的正确姿势是确认服务已停止把现有数据目录改名或移走然后用 initdb 新建D:\PostgreSQL\9.6\bin\initdb.exe -D D:\pgdata\9.6 -E UTF8 --localeC -U postgres执行完再启动服务。这样重建出来的实例server_encoding 是 UTF8lc_collate 和 lc_ctype 都是 C和 Linux 上最常见部署配置基本对齐后续调试省心一大截。为什么这个坑特别值得刷出来单独讲因为它在 Windows 上几乎必踩而且在安装向导里只是一个不起眼的下拉框。装的时候随便下一步后面要用好久来还债。5. 顺手调优让 9.6.10 在 Windows 上更趁手5.1 postgresql.conf 开发机配置模板安装完、能连接这只是开始。开发调试场景下默认配置有两个问题一是内存参数偏保守二是日志信息不够用。我本地一套适合开发机的配置模板大概是这样的shared_buffers 256MB work_mem 8MB maintenance_work_mem 128MB max_wal_size 1GB min_wal_size 80MB log_min_duration_statement 1000 log_line_prefix %t [%p]: user%u,db%d 参数含义和选择理由shared_buffersPostgreSQL 共享缓冲区大小。开发机上不要贪大8GB 内存的机器设 256MB 足够设太高会和操作系统文件缓存争夺内存得不偿失。这个参数修改后需要重启实例。work_mem排序、哈希等操作的内存上限。设 8MB 是小额提升不易触发内存溢出又比默认的 4MB 对复杂查询友好一点。maintenance_work_memVACUUM、CREATE INDEX 时使用的内存。调大可以明显加快索引维护和批量操作但也不能无止境128MB 对开发库绰绰有余。max_wal_size和min_wal_size9.6 已经用这两个参数替代了老式 checkpoint 配置。开发机没必要追求极致的点检频率给 1GB 上限就行。log_min_duration_statement 1000把执行超过 1 秒的 SQL 全部记录下来。调试慢查询时这简直是救命稻草默认值 -1 是什么都不记建议开发环境一定改掉。log_line_prefix给日志加上时间和用户名、数据库名否则查慢 SQL 的时候都分不清是哪条连接产生的。改配置之前先copy D:\pgdata\9.6\postgresql.conf D:\pgdata\9.6\postgresql.conf.bak备份一份这个习惯能让你在改错参数后一分钟内回到可用状态。5.2 pg_ctl 手动启停绕过服务管理器的方法Windows 服务管理器操作起来没什么问题但遇到需要指定参数启动、或者服务界面不配合的时候pg_ctl是更顺手的工具。手动启动pg_ctl -D D:\pgdata\9.6 start -l D:\pgdata\9.6\pg_log\manual.log手动停止pg_ctl -D D:\pgdata\9.6 stop -m fast这里要注意三个具体问题第一pg_ctl start会用当前 Windows 用户身份启动 postmaster。如果你的当前用户对数据目录没有权限启动会直接失败或卡住。Windows 下比较稳的做法是管理员权限的 cmd 里执行或者先确认数据目录 ACL 里包含了当前用户。第二千万不要在服务管理器已经启动了实例的情况下再去执行pg_ctl start。会报错提示另一个 postmaster 已经在运行让你误以为系统出了问题实际只是启动方式混用了。一次会话里选一种方式要么一直用服务管理器要么一直用命令行。第三-m fast是快速关闭它会回滚未提交事务并断开连接这是日常维护推荐的模式。不要轻易用-m immediate那是崩溃恢复场景才用的可能触发 WAL 恢复流程。为什么要掌握手动启停服务起不来的时候正好可以用pg_ctl在前台直接带日志输出启动能更快看到真实报错。另外数据目录里的postmaster.opts文件记录了上次启动参数手动排查时看一眼总没错。5.3 日常备份、恢复与体检命令9.6.10 的维护命令集和后面几个版本差别不大但务必用同版本目录下的工具不要拿新版本的 pg_dump 去备份旧库再拿到新环境恢复前后版本兼容性虽然大体在进步但 9.6 到 16 的跨度足够产生意外。备份用 pg_dumpD:\PostgreSQL\9.6\bin\pg_dump -h 127.0.0.1 -U postgres -F c -f app_backup.dmp appdb恢复用 pg_restore--clean表示先删除目标库中的同名对象再重建D:\PostgreSQL\9.6\bin\pg_restore -h 127.0.0.1 -U postgres -d appdb --clean app_backup.dmp日常体检最常干的一件事是看表膨胀情况SELECT relname, n_live_tup, n_dead_tup FROM pg_stat_user_tables ORDER BY n_dead_tup DESC LIMIT 20;如果发现某张表死元组数量居高不下执行VACUUM (VERBOSE, ANALYZE) your_table;9.6 的 VACUUM 语法和后面版本没太大变化掌握这一套就足够应付开发库的日常维护了。Windows 上还能额外做一件事定期给数据目录所在分区做快照或简单拷贝备份数据目录独立放在 D 盘的好处到这里就完全体现出来了。最后分享一点自己的体会。装完 9.6.10 之后我做的第一件事永远是确认日志和 locale 两个点而不是急着导数据。Windows 上调数据库九成问题都集中在“服务跑没跑、监听有没有、pg_hba 让不让连、日志里怎么说”这四件事上把这四件事串一遍比在网上盲目搜报错快得多。如果你本地还要同时跑多个 PostgreSQL 版本建议端口、数据目录分开管写一个 start.bat/stop.bat 固定命令把pg_ctl -D D:\pgdata\9.6 start -l ...这类指令固化下来后面维护能省下一大堆重复操作。
阅读完成 · 觉得有帮助?
咨询建站