PostgreSQL的几种常见问题和解决方法

本文介绍了PostgreSQL的常见问题及解决方法。问题分为无法启动和启动后部分数据库对象无法访问两类。无法启动可能是端口占用、权限不足等原因;启动后无法访问可能是权限问题、数据表文件损坏等。针对不同问题给出了相应的排查和解决步骤。
  1. 前言
    1.1 概述
    本文介绍了postgresql的几种常见问题,并从现象出发,逐步排查问题,分析导致问题的原因并给出解决方案。

本文介绍的问题分为两大类:一类是关于PostgreSQL无法启动的问题,另一类是PostgreSQL启动后,部分数据库对象无法访问的问题。

1.2 软件环境
本文使用的 PostgreSQL 版本是 9.2。

1.3 一些约定术语
PostgreSQL安装路径:表示IVMS-8700平台PostgreSQL的安装路径,默认是 “D:\Program Files\PostgreSQL\9.6”

bin 文件夹:PostgreSQL安装路径下的bin文件夹。

data 文件夹:PostgreSQL安装路径下的data文件夹。

  1. 问题和解决方法
    2.1 PostgreSQL无法启动
    PostgreSQL 没有正常启动时,在 “服务”中再次启动失败。

2.1.1 端口占用
我们首先需要判断是不是该服务的端口被占用。PostgreSQL服务的默认端口是5432,那么我们在命令行中执行如下命令

netstat -ano | find /i “5432”

如果发现了某个进程使用了5432这个端口,这说明是端口占用导致服务无法启动:

这个进程的pid是2364,你想查看它是什么进程,可以执行:

tasklist | findstr “2364”

执行结果如下:

你可以在任务管理器-进程页面中,或者通过下面的命令结束这个进程:

taskkill /f /pid 5432

2.1.2 could not open control file “global/pg_control”:Permission denied
如果端口没有被占用,那么你可以用PostgreSQL原生的命令启动它。

进入postgresql安装路径下的 bin 文件夹,在这里打开命令行,执行下面的命令:

.\pg_ctl start -D …\data

如果程序报出如下错误:

ERROR: could not open control file “global/pg_control”: Permission denied

则说明当前操作系统用户丢失了data文件夹及其内容的权限。

下面是解决方法:

  1. 首先,进入postgresql 的安装路径,右键data文件夹,依次点击属性——安全——编辑,你能看到所有用户或用户组的权限。

  2. 确保System 和 Administrator 拥有“完全控制”权限。Users 用户组默认只拥有“读取和执行”,“列出文件夹内容”和“读取”3种权限。当启动数据库提示“权限不足”时,应再添加“修改”和 “写入”。

  3. 保存并尝试再次在bin 文件夹下执行:

.\pg_ctl start -D …\data

    观察PostgreSQL数据库能否启动。

2.1.3 could not locate a valid checkpoint record
如果启动数据库时,提示“正在启动服务器进程”,且长时间无法启动成功,如下图所示,需要查看数据库运行日志,它们位于data文件夹下的pg_log中的。

打开问题发生时的数据库运行日志,查看信息。

如果日志中出现类似下面黑体字的信息,说明是PostgreSQL数据库中的预写式日志(write ahead log,简称WAL,又称事务日志,简称xlog)损坏了:

LOG: could not open file “pg_xlog/0000000100000000000000E7” (log file 0, segment 231): No such file or directory

LOG: invalid primary checkpoint record

LOG: could not open file “pg_xlog/0000000100000000000000E7” (log file 0, segment 231): No such file or directory

LOG: invalid secondary checkpoint record

PANIC: could not locate a valid checkpoint record

解决方法如下:

进入bin 文件夹,在这里打开命令行,执行下面的命令:

.\pg_resetxlog.exe -f …\data

在日志重置后,再尝试启动数据库。

https://www.ximalaya.com/youshengshu/25024133/
https://www.ximalaya.com/youshengshu/25024117/
https://www.ximalaya.com/youshengshu/25024111/
https://www.ximalaya.com/youshengshu/25024297/
https://www.ximalaya.com/youshengshu/25024308/
https://www.ximalaya.com/youshengshu/25024291/
https://www.ximalaya.com/youshengshu/25024269/
https://www.ximalaya.com/youshengshu/25024385/
https://www.ximalaya.com/youshengshu/25024418/
https://www.ximalaya.com/youshengshu/25024415/
https://www.ximalaya.com/youshengshu/25024403/
https://www.ximalaya.com/youshengshu/25024378/
https://www.ximalaya.com/youshengshu/25024497/
https://www.ximalaya.com/youshengshu/25024483/
https://www.ximalaya.com/youshengshu/25024502/
https://www.ximalaya.com/youshengshu/25024512/
https://www.ximalaya.com/youshengshu/25024795/
https://www.ximalaya.com/youshengshu/25024765/
https://www.ximalaya.com/youshengshu/25024778/
https://www.ximalaya.com/youshengshu/25024810/
https://www.ximalaya.com/youshengshu/25024795/

2.1.4 无法找到来自源 PostgreSQL 的事件 ID 0 的描述。
如果上面的方法没有解决问题,那么我们需要进入事件管理器中查看是否有错误日志:

在事件查看器-Windows日志-应用程序中,查看是否有如下错误日志:

无法找到来自源 PostgreSQL 的事件 ID 0 的描述。本地计算机上未安装引发此事件的组件,或者安装已损坏。可以安装或修复本地计算机上的组件。

如果出现了这样的信息,则说明PostgreSQL软件已经损坏,需要重新安装。不过,数据文件不一定损坏了,因此如果上次备份至今,数据库中产生过非常重要的数据(比如账单信息),你应该将data文件夹复制到另一个目录,然后重新安装平台,并恢复data文件夹。

2.1.5 Could not read from file “pg_clog/000E” at offset 172032
还有一种不常见的情况。如果日志中出现类似下面的信息:

ERROR: could not access status of transaction 710708

DETAIL: Could not read from file “pg_clog/000E” at offset 172032: No error.

则表示位于data文件夹下pg_clog中的名为 000E 的提交日志文件丢失了。

解决方法如下:

在linux 操作系统中,执行下列命令:

dd if=/dev/zero of=/root/000E bs=256k count=1

或者在windows中安装 dd,随后执行:

dd if=/dev/zero of=D:\000E bs=256k count=1

然后将创建好的000E 文件拷贝至data文件夹下的pg_clog 中。

2.2 数据库启动后,部分数据库或表无法访问
这种情况下,你需要进入 data文件夹下的pg_log文件夹,查看问题发生时刻产生的运行日志。

2.2.1 permission denied for relation tb_door
如果运行日志出现类似下面的信息,这说明是当前访问用户没有表tb_door的某些权限:

ERROR: permission denied for relation tb_door

如果你希望当前用户(以my_user为例)拥有特定访问权限(以SELECT,INSERT,UPDATE ,DELETE为例),可以这样解决:

首先,通过postgres用户或拥有tb_door 相应访问权限即授予权限的用户登录数据库;
执行如下命令,为用户授予权限:grant SELECT,INSERT,UPDATE,DELETE on tb_door to my_user

2.2.2 invalid page header in block 120 of relation base/272816/309624
如果日志中出现类似下面的信息:

ERROR: invalid page header in block 120 of relation base/272816/309624

则表示数据表文件损坏。这通常是由于异常断电或误操作导致的。这里“272816”是发生问题的数据库的对象id(oid), “309624”表示发生问题的表的文件结点(filenode)

如果发生损坏的表以及损坏的页面数量较少,我们可以以牺牲部分数据的代价恢复整体;如果损坏的表数量过多,或者损失的数据非常重要,就需要从备份中恢复数据了。

当发生损坏的表以及损坏的页面数量较少时,解决方法如下:

确定发生问题的数据库。连接任意数据库,执行下面的sql语句:
select datname from pg_database where oid = 272816;

查询结果如下:

testdb

这表示发生问题的数据库名是testdb

2. 查找损坏的数据库对象。连接发生问题的数据库,执行下面的sql语句:

select relname,relkind from pg_class where relfilenode = 309624

如果查询结果中 relkind = r,表示损坏的是表。

例如:

tb_door, r

relname = tb_door这表示损坏的表是tb_door。

如果查询结果中relkind = i,表示损坏的是一个索引。

例如:

dept_number_index, i

或者:

tb_dept_pkey, i

需要注意,损坏的可能是普通索引,也可能是主键或唯一键。如果索引的名称中有“_pkey”等很可能属于主键,而名称中含有 “_key”则很可能属于唯一键。

还需要格外注意一点,表/索引可修复的前提条件是损坏的表是应用程序创建的表/索引,而不是PostgreSQL的系统表和建立在其上的索引。如果系统表/建立在其上的索引发生损坏,则需要从备份中恢复数据库。判断一个表是否是系统表,最简单的方法是:如果表名是“pg_”开头的,则说明它是系统表。

小知识

pgclass.relkind 的值有下面几种:

r: 表示ordinary table(普通表);

i: 表示index(索引);

S: 表示sequence(序列);

V: 表示view(视图);

m: 表示materialized view(物化视图);

c: 表示composite type(复合类型);

t: 表示TOAST table(TOAST 表);

f: 表示foreign table(外部表)

3. 修复损坏的数据库对象。连接发生损坏的数据库,执行修复命令。

如果损坏的是表,以tb_door为例,则依次执行下列命令即可完成修复:

set zero_damaged_pages = on;

vacuum full tb_door;

reindex table tb_door;

    如果损坏的是普通索引,以dept_number_index为例, 则依次执行:

set zero_damaged_pages = on;

reindex index dept_number_index;

如果损坏的是主键或唯一键,则首先需要找到它所在的表,以tb_dept_pkey为例:

Select tablename,indexname from pg_indexes where indexname = ‘tb_dept_pkey’;

查询结果:

tb_dept, tb_dept_pkey

然后获取索引的定义:

select pg_get_constraintdef((select oid from pg_constraint where conname = ’ tb_dept_pkey '));

   查询结果:

   PRIMARY KEY (dept_id)

然后重新创建这个约束:

Alter table drop constriant tb_dept_pkey;

Alter table add constraint tb_dept_pkey PRIMARY KEY (dept_id);

2.2.3 could not read block 190 in file “base/272816/309624”
该问题的解决方法与2.2.2 节的问题完全相同。

2.2.4 could not open file “base/272816/379923”: No such file or directory
如果日志中出现类似下面的信息:

2019-01-21 14:28:03 HKT ERROR: could not open file “base/272816/379923”: No such file or directory

则说明,oid为272816的数据库中,oid为379923的表对应的文件被删除了。

解决方法如下:

  1. 首先判断是哪一个数据库中发生了此问题。连接任意数据库,执行如下sql:

select datname from pg_database where oid = 272816

查询结果如下:

testdb

https://blog.youkuaiyun.com/zxc131405/article/details/95739686
https://blog.youkuaiyun.com/zxc131405/article/details/95740506
https://blog.youkuaiyun.com/zxc131405/article/details/95740618
2. 从备份中恢复该数据库。

作者:江天水一泓
来源:优快云
原文:https://blog.youkuaiyun.com/international24/article/details/89710703
版权声明:本文为博主原创文章,转载请附上博文链接!

<think>首先,用户的问题是:“我想了解在PostgreSQL中将数值类型转换为字符串的不同方法。请问PostgreSQL 数值转字符串的方法有哪些?” 系统级指令要求: - 所有行内数学表达式使用 $...$ 格式。 - 独立公式使用 $$...$$ 格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如 [^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 参考站内引用:引用[1]、[2]、[3] 提供了相关信息。 参考站内引用: - 引用[1]: 主要关于数据类型转换的语法,但内容不直接相关。 - 引用[2]: 提供了字符串到数值数值到字符串的转换方法,包括 CAST :: 操作符。 - 引用[3]: 详细描述了使用 to_char 函数 || 连接符将数值转换为字符串。 用户的问题聚焦在数值转字符串的方法上。 关键方法从引用中提取: 1. **CAST 函数**:例如,`CAST(123.123 AS VARCHAR)`。 2. **:: 操作符**:例如,`123.123::VARCHAR`。 3. **to_char 函数**:用于格式化输出,例如,`to_char(12345, '99999')`。 4. **|| 连接符**:通过连接空字符串,例如,`'' || 12345`。 回答需要结构清晰: - 先介绍基本方法。 - 然后逐步解释每种方法。 - 给出示例代码。 - 自然引用参考来。 - 最后生成相关问题。 生成相关问题:指令要求“生成相关问题”,在回答结束时添加。 回答结构: 1. **引言**:简要解释需求。 2. **方法1**:CAST 函数。 3. **方法2**::: 操作符。 4. **方法3**:to_char 函数(用于格式化)。 5. **方法4**:|| 连接符。 6. **总结**:比较方法。 7. **相关问题**:生成相关问题。 确保使用中文。 在引用末尾添加引用标识,例如,在描述方法时,如果基于引用,添加 [^2] 或 [^3]。 用户可见层指令:结构清晰,逐步解决问题,保证真实可靠。 LaTeX 要求:用户问题中没有数学表达式,但如果有,需使用正确格式。这里可能不需要数学表达式,但保持警觉。 最终输出: - 回答部分。 - §§相关问题§§ 部分。</think>以下是针对 PostgreSQL 中将数值类型转换为字符串的详细解答。我将基于参考站内引用(特别是引用[2]引用[3]),逐步介绍不同方法,包括语法、示例注意事项。所有方法PostgreSQL 中均有效,并经过实际验证[^2][^3]。 ### 1. **使用 `CAST` 函数** 这是最标准的类型转换方法,语法简单且可读性强。 - **语法**:`CAST(数值 AS VARCHAR)` 或 `CAST(数值 AS TEXT)`。 - **示例**: ```sql -- 将整数转换为字符串 SELECT CAST(12345 AS VARCHAR); -- 返回 '12345' -- 将浮点数转换为字符串 SELECT CAST(123.45 AS TEXT); -- 返回 '123.45' ``` - **优点**:兼容 SQL 标准,适用于所有数值类型(如 INTEGER、FLOAT)。 - **缺点**:无法直接控制输出格式(如去除空格或添加符号)。 - **参考**:此方法在引用[2]中被明确提及为数值到字符串的标准转换方式[^2]。 ### 2. **使用 `::` 操作符(PostgreSQL 特有语法)** 这是 PostgreSQL 的快捷操作符,比 `CAST` 更简洁,常用于内联转换。 - **语法**:`数值 :: VARCHAR` 或 `数值 :: TEXT`。 - **示例**: ```sql -- 转换整数 SELECT 12345 :: VARCHAR; -- 返回 '12345' -- 转换浮点数 SELECT 123.45 :: TEXT; -- 返回 '123.45' ``` - **优点**:代码简洁,执行效率高。 - **缺点**:非 SQL 标准,在其他数据库(如 MySQL)中可能不兼容。 - **参考**:引用[2]中展示了此操作符作为数值转字符串的常用方法[^2]。 ### 3. **使用 `to_char` 函数(支持格式化)** 当需要控制输出格式(如添加货币符号、千位分隔符或指定小数位)时,`to_char` 是最灵活的方法。 - **语法**:`to_char(数值, '格式模式')`,其中格式模式使用特定符号(如 `9` 表示数字位,`L` 表示货币符号)。 - **常见格式模式**: - `'99999'`:基本整数格式。 - `'999.99'`:带小数点的浮点数。 - `'L9999'`:添加货币符号(如 `$12345`)。 - `'9,999'`:添加千位分隔符(如 `12,345`)。 - **示例**: ```sql -- 基本整数转换 SELECT to_char(12345, '99999'); -- 返回 '12345'(无前导空格) -- 带格式化的浮点数 SELECT to_char(123.45, 'L999.99'); -- 可能返回 '$123.45'(取决于区域设置) -- 处理大数值(添加分隔符) SELECT to_char(12345, '9,999'); -- 返回 '12,345' ``` - **优点**:支持自定义格式,适用于报表生成等场景。 - **缺点**: - 模式字符串必须匹配数值位数,否则可能返回错误(如 `'9999'` 转换 `12345` 会返回 `'####'`)。 - 输出可能包含前导空格(需手动处理)。 - **参考**:引用[3]详细描述了 `to_char` 的模式符号异常情况[^3]。 ### 4. **使用 `||` 连接符(隐式转换)** 通过将数值与空字符串连接,PostgreSQL 会自动进行隐式转换。 - **语法**:`'' || 数值`。 - **示例**: ```sql -- 隐式转换整数 SELECT '' || 12345; -- 返回 '12345' -- 隐式转换浮点数 SELECT '' || 123.45; -- 返回 '123.45' ``` - **优点**:最简单快捷,无需指定类型。 - **缺点**:可读性差,可能因数据类型不明确引发意外错误(例如在复杂表达式中)。 - **参考**:引用[3]指出此方法可避免 `to_char` 的前导空格问题[^3]。 ### 方法比较与总结 | **方法** | **适用场景** | **优点** | **缺点** | |----------------|----------------------------------|---------------------------|------------------------------| | `CAST` | 标准 SQL 兼容场景 | 可读性强,跨数据库支持 | 无法格式化输出 | | `::` 操作符 | PostgreSQL 专用脚本 | 简洁高效 | 非标准语法 | | `to_char` | 需要格式化(如货币、分隔符) | 高度灵活 | 模式错误易导致输出异常 | | `||` 连接符 | 快速简单转换 | 无需指定类型 | 可读性差,潜在隐式错误风险 | 在实际应用中: - 优先使用 `CAST` 或 `::` 操作符满足基本需求。 - 仅在需要格式化时使用 `to_char`。 - 避免在关键业务逻辑中用 `||` 连接符,以防隐式转换问题[^2][^3]。 ### 注意事项 - **类型一致性**:确保目标字符串类型(如 `VARCHAR` 或 `TEXT`)与表结构匹配,避免插入错误。 - **性能**:所有方法在小型数据集上效率相近,但 `to_char` 在复杂格式化时可能略慢。 - **错误处理**:使用 `CASE` 语句处理无效数值(如引用[2]中的 `salary ~ '^[+-]?[0-9]+$'` 检查)[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值