标签: postgresql

有没有办法在 Postgres 中获取事务提交时间戳?

我有数据拉取功能,可以在 5 秒内根据modified_timestamp列从 Postgres 表中抓取所有数据。它的工作方式如下:

  1. SELECT * FROM my_table WHERE modified_timestamp > _some_persisted_timestamp
  2. _some_persisted_timestamp = CURRENT_TIMESTAMP
  3. 处理从步骤 1接收到的数据
  4. 睡眠 5 秒
  5. 转到步骤 1

其中modified_timestamp使用触发器更新(在任何行更新modified_timestamp变为 之后CURRENT_TIMESTAMP)。它工作正常,直到我注意到CURRENT_TIMESTAMPPostgres 实际上是事务开始时间戳并且一些更新丢失了。他们为什么会迷路?这很简单 - 在我执行查询时,SELECT * FROM my_table WHERE modified_timestamp > _some_persisted_timestamp一些更改已经发生,但modified_timestamp在更新_some_persisted_timestamp之前,因为事务仍在进行中。

当更新对其他事务可见(换句话说,事务提交时间戳)而不是 CURRENT_TIMESTAMP 或 clock_timestamp()时,可以通过在步骤 2 中 分配时间戳来轻松解决此问题。

我阅读了文档,但没有发现与事务提交时间戳相关的任何内容。你能不能给点建议?

顺便说一句,我知道逻辑解码,我知道这种机制在理论上更适合我的需求,但有一些实际问题不允许我使用它。

postgresql timestamp

8
推荐指数
1
解决办法
6037
查看次数

Postgres 会执行在视图中未选择的计算列的计算吗?

我试图了解从视图中选择数据的性能影响,其中视图中的一列是原始表中其他数据的函数。

无论计算列是否在所选列的列表中,是否都会执行计算?

如果我有一张桌子并且视图像这样声明

CREATE TABLE price_data (
    ticker     text,          -- Ticker of the stock
    ddate      date,          -- Date for this price
    price      float8,        -- Closing price on this date
    factor     float8         -- Factor to convert this price to USD
);

CREATE VIEW prices AS 
    SELECT ticker, 
           ddate,
           price,
           factor,
           price * factor as price_usd
    FROM price_data
Run Code Online (Sandbox Code Playgroud)

乘法类似下面的查询来执行?

select ticker, ddate, price, factor from prices
Run Code Online (Sandbox Code Playgroud)

是否有参考以一种方式或另一种方式保证这一点?我正在阅读有关 Postgres 规则系统的文档,但我认为答案确实在于优化器,因为规则系统文档中没有任何内容表明它不会被选中。

我怀疑在上述情况下没有执行计算。我将视图更改为使用除法而不是乘法,并将0for插入factorprice_data. 上面的查询没有失败,但如果修改查询以选择计算列,则修改后的查询失败。

有什么方法可以理解在执行 a 时 …

postgresql view

8
推荐指数
1
解决办法
718
查看次数

Postgres 加速大表的索引创建

我有一个大型 Postgres 表,其中包含 2+ 十亿个条目(1.5TB),并且大部分是非空的 char var 列。为了加快插入速度,我在批量上传之前删除了索引。但是,现在创建 b 树索引需要很长时间。对于我缩短的运行之一,它花了超过 12 个小时创建索引。

我正在尝试制作的示例表和索引:

        Column         |            Type             | Modifiers 
-----------------------+-----------------------------+-----------
 name                  | character varying           | not null
 id                    | character varying           | 
 lifecycle_id          | character varying           | 
 dt                    | character varying           | 
 address               | character varying           | 
 ...

Indexes: 
"name_idx" PRIMARY KEY, btree (name)

"id_idx" btree (rec_id)

"lifecycle_id_idx" btree (lifecycle_id)
Run Code Online (Sandbox Code Playgroud)

实际表有 18 列。我已将 maintenance_work_mem 设置为 15GB。这是在 RDS 上的 Postgres 9.6.11 上运行的。实例类是 db.m4.4xlarge。

由于有三个索引,在插入之前很难对数据进行排序。只插入数据而不删除索引会更快吗?还有其他加快索引创建的建议吗?

postgresql postgresql-9.6

8
推荐指数
3
解决办法
6940
查看次数

Postgres中整数列与布尔列的磁盘使用情况

我看到了这个问题Bit vs. Boolean columns

对于 Postgres,我问自己同样的问题:一位整数列是否占用了布尔值列的相同磁盘空间?在大表(约 50 列 x 约 5000 万行)中,哪一个表现最好?我怎样才能找到这个?

postgresql performance database-design optimization disk-space postgresql-performance

8
推荐指数
1
解决办法
1421
查看次数

更新嵌套在 JSON 对象数组中给定键的所有值

我在 Postgres 表中有一个jsonb列。它包含以下数据:datamy_table

[
   {"id":"1","status":"test status1","updatedAt":"1571145003"},
   {"id":"2","status":"test status2","updatedAt":"1571145323"}
]
Run Code Online (Sandbox Code Playgroud)

我想updatedAt使用一个查询更新该数组中所有对象的键。我试过:

update my_table set data = data || '{"updatedAt": "1571150000"}';
Run Code Online (Sandbox Code Playgroud)

上面的查询在数组中添加了一个新对象,如下所示:

[
   {"id":"1","status":"test status1","updatedAt":"1571145003"},
   {"id":"2","status":"test status2","updatedAt":"1571145323"},
   {"updatedAt":"1571150000"}
]
Run Code Online (Sandbox Code Playgroud)

我想要的输出如下:

[
   {"id":"1","status":"test status1","updatedAt":"1571150000"},
   {"id":"2","status":"test status2","updatedAt":"1571150000"}
]
Run Code Online (Sandbox Code Playgroud)

我也尝试过jsonb_set(),但这需要第二个参数是数组索引。我无法确定数组中 JSON 对象的数量。

如果可以通过自定义函数解决这个问题,也很好。

postgresql update json postgresql-10 json-path

8
推荐指数
2
解决办法
1万
查看次数

如何根据postgresql中另一列的计算添加新列?

我有下表:

id   time_start           area
1   2019-09-01T10:12:32Z  london
2   2019-08-29T10:13:32Z  chicago
3   2019-07-31T10:14:32Z  paris
4   2019-09-28T10:17:32Z  madrid
5   2019-07-04T10:18:32Z  spain
Run Code Online (Sandbox Code Playgroud)

我想添加一个名为 Correct_date 的新列,它只是 time_start 列:

新列应添加到末尾,如下所示:

date_start
2019-09-01
2019-08-29
2019-07-31
2019-09-28
2019-07-04
Run Code Online (Sandbox Code Playgroud)

但是,我事先根据 where 语句过滤数据,并且有点困惑如何在满足 where 条件后更改表 - 或者以哪种顺序执行该过程?我知道我必须使用 timestamp::date 来获取日期。

我当前的查询是

select * 
from 
my_table 
where area in ('london','chicago','paris') 
Run Code Online (Sandbox Code Playgroud)

如何在上面的代码中添加一个 alter table 语句,以便它根据 time_start 列的日期添加一个新列 - 我会在开头执行 alter 语句吗?

使用 postgresql 无法在线找到明确的答案!

postgresql

8
推荐指数
1
解决办法
3万
查看次数

不区分大小写的排序规则仍然比较区分大小写

目前我正在试图创建一个表,一个文本列将比较案例默认情况下是敏感的。这是因为我们有一个第三方程序可以对我们的数据库执行搜索。该SELECT程序使用的语句不能更改。

抽象的问题是我们不知何故需要这个搜索不区分大小写,但它目前是区分大小写的。

我读到 Postgres 12 确实支持允许这种行为的非确定性排序规则。

我在德国 Windows 机器上安装了 Postgres 服务器(版本 PostgreSQL 12.1,由 Visual C++ build 1914 编译,64 位)。

因此,出于测试目的,我创建了一个新数据库进行测试:

CREATE DATABASE collation_test
    WITH 
    OWNER = postgres
    ENCODING = 'UTF8'
    CONNECTION LIMIT = -1;
Run Code Online (Sandbox Code Playgroud)

在这个数据库中,我创建了以下排序规则,我在一篇关于这些排序规则的文章中找到

CREATE COLLATION collat_ci (
  provider = 'icu',
  locale = 'und-u-ks-level2',
  deterministic = false
);
Run Code Online (Sandbox Code Playgroud)

在此之后,我需要一个表来测试这个排序规则

CREATE TABLE public.person
(
    "Id" bigint NOT NULL,
    "Name" text COLLATE public.collat_ci,
    PRIMARY KEY ("Id")
);

ALTER TABLE public.person
    OWNER to postgres;

INSERT …
Run Code Online (Sandbox Code Playgroud)

postgresql collation case-sensitive postgresql-12

8
推荐指数
1
解决办法
1958
查看次数

通过自动递增 PK 排序是否确保按时间顺序排列?

从创建的角度来看,假设在 Postgres 中通过自动递增的 PK 排序将按时间顺序对记录进行排序是否安全?我有一个多对多的关系,除了关系本身和某种形式的创建顺序之外,我不需要跟踪其他任何东西。我正在尝试决定是否需要为此合并时间戳列,或者是否可以出于相同目的重新利用现有的自动递增 PK 列。

postgresql primary-key sequence

8
推荐指数
1
解决办法
911
查看次数

如何找到两种货币之间的最短路径?

我有桌子currency_pair(c1, c2);值是(usd,bnb), (cake,bnb), (cake,eth)

我需要找到一个让我比较的最短路径usdeth

此处的结果将是相同的值。然后我可以使用第一对建立一个 usd-bnb 关系,然后我可以用它来计算 usd-cake 关系,然后我可以用它来计算 usd-eth。

由于顺序是不确定的,我做的第一步是创建一个物化视图,currency_pair_map(c1, c2),它是 的并集select c1, c2 union select c2, c1。这似乎简化了逻辑。

如果我正确考虑这一点,我需要做的是使用WITH RECURSIVE?我还应该有某种“depth_limit”参数,以确保在无法建立一对时查询失败。

大声思考这个问题,我们应该始终从以下几点开始:

SELECT *
FROM currency_pair
WHERE
  c1 = 'usd' AND
  c2 = 'eth'
Run Code Online (Sandbox Code Playgroud)

如果有结果,我们应该到此为止。

如果没有,那么我们需要找到所有usd-*对并继续搜索,直到找到以 结尾的对eth

使用这个逻辑,到目前为止我有:


WITH RECURSIVE pair_route AS (
  SELECT
    1 depth,
    cp1.id,
    cp1.c1,
    cp1.c2
  FROM currency_pair cp1
  WHERE
    cp1.c1 = 'usd'
  UNION
  SELECT
    pr1.depth + 1, …
Run Code Online (Sandbox Code Playgroud)

postgresql recursive

8
推荐指数
1
解决办法
901
查看次数

检测内联、内联压缩和 TOAST 存储

想象一下,我在 Postgres 13 中有一个像这样的表:

CREATE TABLE public.people (
    id integer PRIMARY KEY,
    full_name character varying(255),
    bio text
);
Run Code Online (Sandbox Code Playgroud)

然后,我插入一行,其中包含足够的字符,以便将 Bio 写入 TOAST 表(4000 个随机字节,应压缩到 > 2Kb):

# insert into people values (1, 'joe toast', (SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,4000)), '')));
INSERT 0 1
Run Code Online (Sandbox Code Playgroud)

然后插入一行,其中包含足够的字符用于 Bio Fit 内联(3000 个重复字节,应压缩至 < 2Kb):

# insert into people values (2, 'joe compressed', (SELECT array_to_string(ARRAY(SELECT chr(65) FROM generate_series(1,3000)), '')));
INSERT 0 1
Run Code Online (Sandbox Code Playgroud)

最后在简介中插入一行仅包含几个字符的行,以便它将存储内联(10 个重复字节):

# insert into people values …
Run Code Online (Sandbox Code Playgroud)

postgresql

8
推荐指数
1
解决办法
1095
查看次数