相关疑难解决方法(0)

RDS 上非常慢的简单 PostgreSQL 查询

我似乎在中型 RDS 盒子(db.m3.medium,3.7gb ram)上的查询速度很慢。

这是一个包含 4,152,928 行的表格。

select sum(some_field) c
from pages
where pages.some_id=123
and pages.first_action_at > '2014-01-01 00:00:00 +1000'
Run Code Online (Sandbox Code Playgroud)

总运行时间:45031 毫秒。
在本地,我有大约 110 万行,同样的查询需要大约 450 毫秒。

这是查询计划,来自解释:

Aggregate  (cost=475640.59..475640.60 rows=1 width=4)
   ->  Seq Scan on pages  (cost=0.00..475266.07 rows=149809 width=4)
         Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time zone) 
                AND (some_id = 447))
Run Code Online (Sandbox Code Playgroud)

这是来自解释分析的回应:

 Aggregate  (cost=475641.74..475641.76 rows=1 width=4) (actual time=42419.717..42419.718 rows=1 loops=1)
   ->  Seq Scan on pages  (cost=0.00..475267.22 rows=149810 width=4) (actual time=0.013..42265.908 rows=141559 loops=1)
    Filter: ((first_action_at > '2014-01-01 00:00:00'::timestamp without time …
Run Code Online (Sandbox Code Playgroud)

postgresql performance index index-tuning postgresql-performance

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

Postgres - 使用索引插入性能

我们在 Postgres 9.2.10 数据库中有一个大约有 20 列的表。为了在某​​些SELECT查询上获得更好的性能,我们计划在数据类型为 的列上添加索引timestamp。由于索引也会降低插入的性能,我们做了以下性能测试:

我们在表中插入了 500 万条记录。那是最大值。我们期望在生产中的记录数。然后我们测量了在时间戳列上插入有索引和没有索引的 10000 条记录的时间。这是我们每天预期的最大插入次数,峰值每秒不超过 5 次插入。

结果如下:

  • 带索引 - 84 441 毫秒
  • 无索引 - 78 000 毫秒

至少对于本次测试,该指数仅略微降低了性能。对于我们的要求,我没有看到添加索引的问题。

但这只是实验室环境中的一项测试,在生产数据库上运行时是否还有其他陷阱?我们是否会遇到INSERT在特定情况下突然需要超过 5 秒的情况?

postgresql performance index index-tuning query-performance

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

文本列比较等于 where 子句但不选择匹配行

我们在查询生产数据库中的表时遇到问题。一个文本列将与我们在 where 子句中过滤的字符串相等,但 postgres 不会选择该行。(我们在 postgres 11.11 上)我们的表设置如下:

(PROD)=> \d names;
                           Table "public.names"
        Column        |            Type             | Collation | Nullable | Default
----------------------+-----------------------------+-----------+----------+---------
 name                 | text                        |           | not null |
 processed_name       | text                        |           | not null |
 name_index           | integer                     |           | not null |
 when_created         | timestamp without time zone |           | not null |
Indexes:
    "names_pkey" PRIMARY KEY, btree (name, processed_name)
    "names_name_index_key" UNIQUE CONSTRAINT, btree (name_index)
    "ix_names_name" btree (name)
    "ix_names_processed_name" btree (processed_name)
Run Code Online (Sandbox Code Playgroud)

当我们处理名称列表时,我们会检查它们是否已经在表中,以防止重复添加和违反主键约束。

然而,在一个名字上,'?????? ????????? ???????',查看名称是否已经存在的查询返回一个空集, …

postgresql string

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

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

我有一个分区表...

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
查看次数

Postgres 9.4.4 查询需要永远

我们在 CentOS 6.5 上运行 Postgres 9.4.4 并且有一个已经工作多年的 SELECT 查询,但在我们从 9.2 升级后停止工作并挂起(花了一段时间才注意到它,所以我不知道它是否是我们升级与否后立即)。

SELECT id || ':' || group_number AS uniq_id
FROM   table_one
WHERE  id || ':' || group_number NOT IN (
   SELECT id || ':' || group_number
   FROM table_two
   )
AND    id NOT IN (
   SELECT id
   FROM table_three
   WHERE timestamp > NOW() - INTERVAL '30 days' 
   AND client_id > 0
   );
Run Code Online (Sandbox Code Playgroud)

在所有表中id都是一个整数,但存储为character varying (15)(旧系统)。group_number存储为smallint.

table_two 的子查询返回大约 250 万条记录。的子查询table_three返回大约 2,500 条记录。如果单独运行,两者都在大约 …

postgresql performance postgresql-9.4 query-performance

5
推荐指数
1
解决办法
3495
查看次数

聚合一列中在另一列中没有匹配项的丢弃值

说,我有一个表格,代表编号框中的彩色和标记的项目。
每个盒子不能包含多个带有特定标签的物品,但具有相同标签(以及相同或不同颜色)的物品在其他盒子中可能是唯一的。

过度简化,使用 PostgreSQL,我们可以得到下表:

CREATE TABLE items (
    label character varying,
    color character varying,
    box_number integer
);
INSERT INTO items VALUES
  ('a','red',1),
  ('b','blue',1),
  ('c','blue',1),
  ('a','red',2),
  ('c','green',2),
  ('d','blue',2),
  ('b','red',3),
  ('d','green',3);
Run Code Online (Sandbox Code Playgroud)

我想知道编号为 3 的箱子内所有物品的标签和颜色,以及可以找到具有相同标签的物品的所有箱子编号。换句话说,我试图:

SELECT label, boxes
FROM (
  SELECT label, array_agg(DISTINCT box_number) AS boxes
  FROM items
  GROUP BY label
) AS sub1
WHERE 3 = ANY(boxes);
Run Code Online (Sandbox Code Playgroud)

但我还需要返回color列,仅显示框号 3 内项目的颜色。

对于示例数据,输出应该是这样的:

标签 | 颜色 | 盒子
------+-------+------
乙 | 红色 | 1,3
d | 绿色| 2,3

这是示例SQL …

postgresql aggregate

5
推荐指数
1
解决办法
233
查看次数

Postgres 有时对 WHERE a IN (...) ORDER BY b LIMIT N 使用劣等索引

我们有一个包含约 50 亿行的 PostgreSQL 表,它养成了一个讨厌的习惯,即缺少正确的索引并对某些LIMIT操作进行主键扫描。

问题通常出现在一个ORDER BY .. LIMIT ..子句(Django 分页中的常见模式)上,其中LIMIT是索引匹配的结果的一些相对较小的子集。一个极端的例子是这样的:

SELECT * FROM mcqueen_base_imagemeta2 
  WHERE image_id IN ( 123, ... )
  ORDER BY id DESC
  LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

其中该IN子句中的项目约为 20,索引匹配的总行数image_id为 16。

EXPLAIN表明,它错过了image_id指数,而是确实5B行的PK扫描:

限制(成本=0.58..4632.03 行=1 宽度=28)
   -> 在 mcqueen_base_imagemeta2 上使用 mcqueen_base_imagemeta2_pkey 向后扫描索引(成本=0.58..364597074.75 行=78722 宽度=28)
         过滤器:(image_id = ANY ('{123, ...}'::bigint[]))

如果LIMIT增加到2,它会按预期工作:

限制(成本=7585.92..7585.93 行=2 宽度=28)
   -> 排序(成本=7585.92..7782.73 行=78722 宽度=28)
         排序键:id DESC
         -> 在 mcqueen_base_imagemeta2 上使用 …

postgresql performance index-tuning paging postgresql-9.6 query-performance

5
推荐指数
2
解决办法
531
查看次数

为什么 10,000 个 ID 的列表比使用等效的 SQL 来选择它们的性能更好?

我有一个带有遗留查询的 Rails 应用程序,我想对其进行翻新。当前实现执行两个 SQL 查询:一个获取大量 ID,第二个查询使用这些 ID 并应用一些额外的连接和过滤器来获得所需的结果。

我试图用避免往返的单个查询替换它,但这样做会导致我的本地测试环境(这是完整生产数据集的副本)的性能大幅下降。新查询中似乎没有使用索引,导致全表扫描。我曾希望单个查询能够保持与原始代码相同的性能,理想情况下,由于不需要发送所有 ID,因此可以对其进行改进

这是我实际问题的最小化版本。稍大一点的版本在讨论为什么10000个ID的列表中一个复杂的查询有更好的表现与多个热膨胀系数相比,相当于SQL选择它们?.

当前查询

有一个查询需要大约 6.5 秒来计算 10000 多个 ID 的列表。您可以visible_projects在下面的“建议查询”部分中将其视为 CTE 。然后将这些 ID 输入到此查询中:

EXPLAIN (ANALYZE, BUFFERS)
WITH visible_projects AS NOT MATERIALIZED (
    SELECT
        id
    FROM
        "projects"
    WHERE
        "projects"."id" IN (
            -- 10000+ IDs removed
)),
visible_tasks AS MATERIALIZED (
    SELECT
        tasks.id
    FROM
        tasks
    WHERE
        tasks.project_id IN (
            SELECT
                id
            FROM
                visible_projects))
SELECT
    COUNT(1)
FROM
    visible_tasks;
Run Code Online (Sandbox Code Playgroud)

查询计划(depesz

Aggregate  (cost=1309912.31..1309912.32 rows=1 width=8) (actual time=148.661..153.739 …
Run Code Online (Sandbox Code Playgroud)

postgresql performance query-performance postgresql-performance

5
推荐指数
1
解决办法
113
查看次数

PostgreSQL 可以使用索引来加速计数(不同)查询吗?

考虑以下示例:

CREATE TABLE test (
  id SERIAL,
  some_integer INT
);

INSERT INTO test (some_integer)
SELECT FLOOR(RANDOM()*100000) from generate_series(1,100000) s(i);

CREATE INDEX some_integer_idx ON test (some_integer);

EXPLAIN ANALYZE SELECT COUNT(DISTINCT some_integer) from test;
Run Code Online (Sandbox Code Playgroud)

它返回以下查询计划:

CREATE TABLE test (
  id SERIAL,
  some_integer INT
);

INSERT INTO test (some_integer)
SELECT FLOOR(RANDOM()*100000) from generate_series(1,100000) s(i);

CREATE INDEX some_integer_idx ON test (some_integer);

EXPLAIN ANALYZE SELECT COUNT(DISTINCT some_integer) from test;
Run Code Online (Sandbox Code Playgroud)

我很惊讶它仍然在测试中进行顺序扫描。简单地计算索引中的行数不是更快吗?

postgresql index count distinct

5
推荐指数
1
解决办法
1593
查看次数

静态大型 PostgreSQL 表的查询性能

我试图尽可能详细地说明这一点。抱歉长度!

背景

protein_snp_assoc我在 PostgreSQL(版本 12.13)数据库上创建了以下分区表:

CREATE TABLE protein_snp_assoc (
  protein_id    int not null,
  snp_id        int not null,
  beta          double precision,
  se            double precision,
  logp          double precision
) PARTITION BY RANGE (snp_id);
Run Code Online (Sandbox Code Playgroud)

然后,我根据以下模板创建了 51 个分区,每个分区包含大约 1.5 亿行(总共 76.5 亿行):

CREATE TABLE IF NOT EXISTS protein_snp_assoc_(x) PARTITION OF protein_snp_assoc
  FOR VALUES FROM (y) TO (z);
Run Code Online (Sandbox Code Playgroud)

其中x范围从 1 到 51,并y, z定义间隔,每个长度为 150,000。例如,前两个和最后一个分区是:

protein_snp_assoc_1 FOR VALUES FROM (1) TO (150001),
protein_snp_assoc_2 FOR VALUES FROM (150001) TO (300001), ...
protein_snp_assoc_51 …
Run Code Online (Sandbox Code Playgroud)

postgresql database-design read-only-database query-performance postgresql-performance

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