标签: postgresql-performance

寻找更简单的递归查询替代方案

实际查询更多,但我面临的问题可以归结为:

用于过滤单调递增整数行集的查询,以便 -在最终结果集中, row(n+1).value >= row(n).value + 5

对于我需要解决的实际问题,行集计数在 1000 秒内。

举几个例子来澄清:

  • 如果行是: 1,2,3,4,5 :那么查询应该返回:1
  • 如果行是: 1,5,7,10,11,12,13 :那么查询应该返回:1,7,12
  • 如果行是:6,8,11,16,20,23:那么查询应该返回:6,11,16,23
  • 如果行是:6,8,12,16,20,23:那么查询应该返回:6,12,20

我设法通过以下查询获得了所需的结果,但它似乎过于复杂。取消注释不同的“..with t(k)..”以尝试它们。

我正在寻找任何简化或替代方法来获得相同的结果。

with recursive r(n, pri) as (
    with t(k) as (values (1),(2),(3),(4),(5))   -- the data we want to filter
    -- with t(k) as (values (1),(5),(7),(10),(11),(12),(13))
    -- with t(k) as (values (6),(8),(11),(16),(20),(23))
    -- with t(k) as (values (6),(8),(12),(16),(20),(23))
    select min(k), 1::bigint from t             -- bootstrap for recursive processing. 1 here represents rank().
    UNION
    select k, (rank() over(order …
Run Code Online (Sandbox Code Playgroud)

postgresql performance cte recursive postgresql-performance

7
推荐指数
1
解决办法
2098
查看次数

过滤 UNION ALL 结果比过滤每个子查询慢得多

编辑:请参阅结尾以获得更简单的示例)

我在一个名为“cases”(135k 行,29 列)的表中搜索。此表中的某些行具有父子关系类型(不同类型),这意味着对于这些记录,必须混合使用父/子字段来过滤和显示。

我已经确定了四种不同的父子关系并为它们创建了视图:

  • caselist_no_specials:不是子记录,按原样使用记录数据;总共 116106 行。
  • caselist_disputes_with_ipr:子记录;共 138 行。
  • caselist_mark_children:子记录;总共 18132 行。
  • caselist_design_children:子记录;共 671 行。

这些视图的结果不重叠,共同覆盖了表格的 100%。

当我选择所有这些的联合并分别过滤每个视图时,查询需要大约 9 毫秒。选择所有视图的联合并过滤其结果大约需要 500 毫秒。

我还在没有视图的情况下对此进行了测试,内联了它们包含的查询,但没有产生可衡量的改进。

这是快速查询(解释):

  SELECT  c.*
    FROM  caselist_no_specials c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

   UNION ALL

  SELECT  c.*
    FROM  caselist_disputes_with_ipr c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id = 12046

   UNION ALL

  SELECT  c.*
    FROM  caselist_mark_children c
    JOIN  case_clients cacl ON cacl.case_id = c.main_id
   WHERE  cacl.client_id …
Run Code Online (Sandbox Code Playgroud)

postgresql performance view union postgresql-performance

7
推荐指数
1
解决办法
3712
查看次数

多列时间戳索引上的 min()/max()

我发现很难理解为什么在这个查询中进行了一堆堆提取。据我了解,当索引中没有空值(两端)时,反向搜索索引应该与直接搜索一样快,反之亦然。

我怀疑向前/向后扫描实际上是一个红鲱鱼,但我无法识别此解释输出中的任何其他有意义的差异。

这是表格布局。我已将我认为与问题无关的前两列匿名化,但为了完整起见,我保留了它们及其索引。

testqueuedb=> \d+ queue
                                                                  Table "public.queue"
        Column         |           Type           |                          Modifiers                          | Storage  | Stats target | Description
-----------------------+--------------------------+-------------------------------------------------------------+----------+--------------+-------------
 foo                   | character varying(64)    | not null                                                    | extended |              |
 bar                   | numeric(6,0)             | not null                                                    | main     |              |
 worker                | character varying(32)    | not null                                                    | extended |              |
 queued                | timestamp with time zone | not null default (timeofday())::timestamp without time zone | plain    |              |
Indexes:
    "queue_idx_job" btree (foo, bar, worker)
    "queue_idx_worker" btree (worker, …
Run Code Online (Sandbox Code Playgroud)

postgresql performance postgresql-performance

7
推荐指数
1
解决办法
599
查看次数

PostgreSQL 在没有 jsonb_set 的情况下更新 JSONB

使用普通的更新语句来更新 json(b) 列是否有任何缺点,如下所示:

update "events" set "properties" = '{"type":"graph"}'
Run Code Online (Sandbox Code Playgroud)

而不是使用 PostgreSQL 提供的 jsonb_set 函数,它会变成这样的语句:

update "events" set jsonb_set("properties", {'type'}, 'graph')
Run Code Online (Sandbox Code Playgroud)

当使用例如。一个 ORM,并在刚刚更新了 JSON 字段的模型上调用 .save(),第一个方法将被调用,但是由于 PostgreSQL 文档中没有提到这种做事方式,我担心这个可能有一些缺点。

鉴于我对数据库性能方面的任何事情都不太熟悉,我想我会来这里问一个问题。

提前致谢!

postgresql performance json postgresql-performance

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

为什么 PostgreSQL 9.5 不使用我最新的 ORDER BY 索引,即使它使用类似的索引就好了?

(这篇文章的后续内容:当我在子查询中 ORDER BY 时,为什么我的 PostgreSQL 表达式索引没有被使用?

PostgreSQL 9.5。

我不能透露全部细节,但table有 22 列和 5 个索引:

  1. 主键 ('pk'), text(btree)
  2. 另一个text(btree)
  3. 一个timestamp with time zone(btree)
  4. 一个tsvector(杜松子酒)
  5. 我最新的一个bigint(btree)

(从上一篇文章你知道我试图避免创建这个额外的列,只是使用表达式索引——将两integer列加在一起——没有成功。bigint这里的列可能只是“整数”,但我做了一个创建它时出错;添加列、填充它并重新编制索引花了大约一个小时,所以我希望这不相关,但要提及它以防万一。)

除了tsvector.

以下查询都只需要 12ms 并且只使用一个Index Scan

  1. SELECT pk FROM table ORDER BY pk DESC LIMIT 10
  2. SELECT pk FROM table ORDER BY text_column DESC LIMIT 10
  3. SELECT pk FROM table ORDER BY timestamp_column DESC LIMIT 10 …

postgresql performance index optimization postgresql-9.5 postgresql-performance

7
推荐指数
1
解决办法
382
查看次数

如何通过子查询或连接来利用分区修剪?

我有一个分区表...

CREATE TABLE erco.rtprices
(
    scedtime timestamp with time zone NOT NULL,
    node_id integer NOT NULL,
    lmp numeric(12,6),
    CONSTRAINT rtprices_pkey PRIMARY KEY (scedtime, node_id)
) PARTITION BY LIST (node_id);
Run Code Online (Sandbox Code Playgroud)

每个都有node_id自己的分区。

如果我进行直接查询(第一个版本),例如:

explain select scedtime, lmp 
from erco.rtprices
where node_id = 11111
Run Code Online (Sandbox Code Playgroud)

然后该计划仅对rtprices_11111分区进行顺序扫描。 这就是我要的。

但是,如果我执行(第二个版本)查询,例如

explain select scedtime, lmp 
from erco.rtprices
inner join erco.nodes using (node_id)
where nodename = 'somename'
Run Code Online (Sandbox Code Playgroud)

那么该计划包括对每个分区进行顺序扫描,即使此查询与第一个查询一样有限制。

我尝试了上述查询的另一种形式(第三个版本)。

explain select scedtime, lmp 
from erco.rtprices
where node_id = (select node_id from erco.nodes where nodename='somename') …
Run Code Online (Sandbox Code Playgroud)

postgresql execution-plan partitioning postgresql-performance postgresql-13

6
推荐指数
1
解决办法
1714
查看次数

COUNT(1) OVER (PARTITION BY NULL) 的性能损失

在我的应用程序服务器中,我想使用LIMIT和对数据集进行分页OFFSET,并另外将数据集的总数返回给用户。

而不是对数据库进行两次远程调用:

select count(1) as total_count from foo;
select c1 from foo;
Run Code Online (Sandbox Code Playgroud)

我认为在单个数据库调用中完成此操作会更明智:

select c1, count(1) over (partition by null) from foo;
Run Code Online (Sandbox Code Playgroud)

但是,与不使用窗口函数相比,添加此窗口函数会导致执行时间长一个数量级。

我觉得这很令人惊讶,因为类似的时间select count(1) from foo只需要两倍的时间select c1 from foo。然而,将其转换为窗口函数会导致性能下降。

此外,使用以下使用子查询的替代方案非常快:

select c1, (select count(1) from foo) as total_count from foo;
Run Code Online (Sandbox Code Playgroud)

我本来期望 postgresql 能够优化partition by null

我在 Oracle 中尝试过这一点,发现了类似的性能损失。

如何解释为什么这里会出现性能损失?对于核心 postgresql 开发人员来说,进行更改以优化这一点是否相对容易,甚至值得,例如通过将 PARTITION BY NULL 的窗口函数转换为子查询?


设置:

drop table foo;
create table foo (c1 int);

insert into foo
select i from …
Run Code Online (Sandbox Code Playgroud)

postgresql count window-functions postgresql-performance postgresql-13

6
推荐指数
1
解决办法
4772
查看次数

如何通过许多重复的 UNION 子查询来减少查询大小?

我使用 Postgres 13 并使用以下 DDL 定义了一个表:

CREATE TABLE item_codes (
    code    bytea                    NOT NULL,
    item_id bytea                    NOT NULL,
    time    TIMESTAMP WITH TIME ZONE NOT NULL,
    PRIMARY KEY (item_id, code)
);

CREATE INDEX ON item_codes (code, time, item_id);
Run Code Online (Sandbox Code Playgroud)

我使用以下查询:

SELECT DISTINCT time, item_id
FROM (
      (SELECT time, item_id
       FROM item_codes
       WHERE code = '\x3965623166306238383033393437613338373162313934383034366139653239'
       ORDER BY time, item_id
       LIMIT 100)
       UNION ALL
      (SELECT time, item_id
       FROM item_codes
       WHERE code = '\x3836653432356638366638636338393364373935343938303233343363373561'
       ORDER BY time, item_id
       LIMIT 100)
     ) AS items
ORDER …
Run Code Online (Sandbox Code Playgroud)

postgresql execution-plan union query-performance postgresql-performance

6
推荐指数
1
解决办法
608
查看次数

为什么 PostgreSQL 数据库表上的“DELETE”操作异常缓慢?

在 PostgreSQL 数据库表上执行“DELETE”操作时,我遇到了严重的性能问题。删除 15488 条记录的执行时间为 79423.768 毫秒,与“INSERT”或“SELECT”等其他操作相比非常慢。对于为什么会发生这种情况以及优化删除操作的可能方法,我将不胜感激。

背景:我使用 PostgreSQL 引擎版本 12.14 作为应用程序的后端,并且我注意到从一个表中删除记录需要花费出乎意料的长时间。涉及的表定义了索引和约束,数据库大小相对较小,预计会增长到几 GB。然而,对于这个特定的表,这个问题似乎更加明显,而其他表则表现良好。

硬件是 AWS db.t2.micro 实例,具有 1 个 CPU 核心、1 (GiB) 内存和 20 (GiB) 通用 SSD 用于存储。

column_name_loading表架构,我们尝试从中删除的表。

列名称 数据类型 描述
ID 文本 首要的关键
散列 文本 首要的关键
日期_从 时间戳 首要的关键
日期到 时间戳
测量位置uuid 通用唯一标识符 主键、外键
列名 文本 不为空
统计类型id 文本
被忽略 布尔值
笔记 文本
更新时间 时间戳
更新者 通用唯一标识符

可以看到,上表有一个复合主键,涉及4列。有两个表具有对该column_name_loading表的外键引用

第一桌

ALTER  TABLE
logger_main_config_column_name_loading 
ADD
CONSTRAINT column_name_loading_fkey FOREIGN KEY (
column_name_loading_measurement_location_uuid,
column_name_loading_id,
column_name_loading_hash,
column_name_loading_date_from
) REFERENCES …
Run Code Online (Sandbox Code Playgroud)

postgresql delete postgresql-performance slow-query

6
推荐指数
1
解决办法
2478
查看次数

Postgres 中违反唯一键约束是否会导致性能损失?

在我的 API 中,当存在具有该唯一键的行时,用户可能会发送一个尝试创建新行的请求。

目前,我正在捕获唯一键错误并返回一条消息,指出 X 已存在。但是,首先查找该行(在同一连接上)并且仅在该行不存在时才运行 INSERT 语句是否会更高效?

我的直觉告诉我,从 PostgreSQL 读取错误应该会更有效,但我想确保我正在按照惯用的方式做事。

PostgreSQL 版本为 12

我的 API 中的唯一键不是代理 ID 值,它是由外键与文本值组合而成的组合。如果唯一键约束没有失败,数据库确实已经为此行生成了自己的代理 ID 。所以该行的 ID 不是我要检查的内容。正确的行为是不插入行,因为 FK/文本值在表中需要是唯一的。如果请求包含表中已存在的 FK/文本值,则不应插入任何行。

postgresql postgresql-performance

6
推荐指数
3
解决办法
1712
查看次数