标签: postgresql-performance

Postgres 批量更新插入性能

我正在对一个包含 3000 万行的表进行批量 UPSERT。该表只有两列(varchar 作为主键和整数)。首先将输入数据导入到临时表中,然后执行批量更新插入(使用 INSERT ... ON CONFLICT DO UPDATE 语句)。批量大小为 4000。

我的问题是 - 您能给我哪些性能建议?当表较小时(5-1000万条记录),性能就足够好了。对于 3000 万行,这还不够好,单批 4000 条记录持续 2 到 30 秒。

当然,我几乎没有并行执行此导入的服务,因此我使用咨询锁来同步它们(一次仅执行一个批量更新插入)。我是否应该删除咨询锁以并行执行更新插入?然后我将不得不处理死锁(并使用较小的批量大小来减少死锁机会?)。

我可以采取哪些措施来提高批量更新插入的性能?

这是我的大表:

CREATE TABLE my_big_table (
  sender VARCHAR(30) PRIMARY KEY,
  count  INTEGER NOT NULL DEFAULT 0
)
WITH (
  fillfactor = 80,
  autovacuum_vacuum_scale_factor = 0,
  autovacuum_vacuum_threshold = 40000
);
Run Code Online (Sandbox Code Playgroud)

这是 UPSERT 查询:

INSERT INTO my_big_table AS MBT (sender, count)
    SELECT destination, count(*) as received_count
    FROM my_temp_table
    GROUP BY destination
ON CONFLICT (sender) DO UPDATE
    SET …
Run Code Online (Sandbox Code Playgroud)

postgresql performance update upsert postgresql-performance

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

PostgreSQL 中的递归查询性能不佳

我在 PosgreSQL 中的递归查询性能很差。

psql --version
psql (PostgreSQL) 10.7 (Ubuntu 10.7-1.pgdg16.04+1)
Run Code Online (Sandbox Code Playgroud)

这个想法是拥有树状的评论结构。所以什么时候parent_idNULL父评论,什么时候是整数,什么时候是回复。

我的评论表()的表结构如下\d+ comment

     Column      |           Type           | Collation | Nullable |               Default               | Storage  | Stats target | Description 
-----------------+--------------------------+-----------+----------+-------------------------------------+----------+--------------+-------------
 id              | bigint                   |           | not null | nextval('comment_id_seq'::regclass) | plain    |              | 
 website_page_id | bigint                   |           | not null |                                     | plain    |              | 
 author_id       | bigint                   |           | not null |                                     | plain    |              | 
 parent_id       | bigint                   |           |          |                                     | …
Run Code Online (Sandbox Code Playgroud)

postgresql performance postgresql-performance

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

长时间运行的 READ 查询陷入“事务中空闲”状态

我在 Web API 中有一个 JDBC 连接池,它经常向 RDS 实例发出请求。每个请求都是针对长时间运行的 SQL 查询,其中 PG 决定不使用索引,因为要返回的数据量非常大。

我注意到其中一些长时间运行的查询只是停留在 state idle in transaction。当在表中查找pid这些进程时pg_locks,它们有 152 行。带模式AccessShareLock

该表的目的是永远不会更新——它充当时间表中的一个点。所以我认为不需要idle transactionor accesssharelock。我是否可以关闭这些功能,以便我的查询运行得更快并且不会因为AccessShareLock?

postgresql performance postgresql-performance

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

Postgres 10 - 查询因 order by 而变慢

我正在运行一个查询,例如

select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d';
Run Code Online (Sandbox Code Playgroud)

在桌子上看起来像

                Table "public.students"
          Column       |            Type             |             Modifiers              
    -------------------+-----------------------------+------------------------------------
     id                | uuid                        | not null default gen_random_uuid()
     school_id        | uuid                        | 
Indexes:
    "students_pkey" PRIMARY KEY, btree (id)
    "students_school_id_idx" btree (school_id)
Run Code Online (Sandbox Code Playgroud)

select 语句的查询计划与 where 类似,如下所示:

explain select id from students where school_id='67153fb1-8f79-441d-a747-ca3778cf6d3d';
                                            QUERY PLAN                                            
--------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on students  (cost=581.83..83357.10 rows=24954 width=16)
   Recheck Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
   ->  Bitmap Index Scan on students_school_id_idx  (cost=0.00..575.59 rows=24954 width=0)
         Index Cond: (school_id = '67153fb1-8f79-441d-a747-ca3778cf6d3d'::uuid)
Run Code Online (Sandbox Code Playgroud)

这相当快。

现在我们将 …

postgresql postgresql-performance

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

未使用时间戳列上的 Postgres 索引

我有一个数据库,其中有一列名为timestamptype timestamp without timezone,该列上有一个 btree 索引。

我有一个查询如下

SELECT
   *
FROM
  employee 
WHERE 
  timestamp >= timestamp '2020-01-27 13:24:09'
Run Code Online (Sandbox Code Playgroud)

timestamp但是,解释分析显示未使用该列上的索引:

Seq Scan on employee  (cost=0.00..5498.73 rows=34377 width=381) (actual time=0.016..37.944 rows=34251 loops=1)
   Filter: ("timestamp" >= '2020-01-27 13:24:09'::timestamp without time zone)
   Rows Removed by Filter: 21167
 Planning Time: 0.255 ms
 Execution Time: 40.277 ms
Run Code Online (Sandbox Code Playgroud)

如果我使用包含时间戳的过滤条件更改查询,而不是1 month1 year如上所述),则使用列上的索引。

Bitmap Heap Scan on employee  (cost=59.51..4510.25 rows=2996 width=381) (actual time=2.164..5.204 rows=2958 loops=1)
   Recheck Cond: ("timestamp" >= '2020-12-27 13:24:09'::timestamp without …
Run Code Online (Sandbox Code Playgroud)

postgresql index index-tuning postgresql-performance

5
推荐指数
0
解决办法
2609
查看次数

PostgreSql 在运行时更改相同的查询计划

我这里有一个非常奇怪的问题。我们的搜索查询接收多个参数并通过不同表中的多个联接进行搜索。查询在我们运行的前几次运行良好,然后有时会严重减慢,例如:从 200 毫秒到 15000/20000 毫秒。在同一个查询上。

最初我认为这是后端 ORM 问题,但在彻底检查并打开慢速查询日志、打开 auto_explain 功能后,我意识到查询计划在几次调用后发生了变化。我们在后端放置一个循环,在同一线程上多次执行查询(用于测试),我发现几乎总是在执行 8 次后数据库开始记录慢速查询。最后结果是查询计划发生了变化。最重要的变化是(我认为)TimeSlots 表上的变化,从 seq 扫描到位图索引扫描,它估计的行数比表中的行数少得多。估计:566 实际:100 000 左右。

我之前尝试过的事情:

  • 将硬件从 2 核 6GB 升级到 8 核 26GB 内存(100GB SSD)
  • 禁用任何其他应用程序(从而停止任何其他负载)访问它。
  • 在表上执行手动(也有自动运行的作业)VACUUM、ANALYZE、REINDEX。
  • 设置各个列的统计信息,例如SlotDateTime(至10000)
  • 创建不明确的统计数据。
  • 增加了 work_mem、maintenance_work_mem、shared_buffers 大小。
  • 将 seq_page_cost 减少到 1。

这是选择语句:

SELECT DISTINCT u."UserId"     AS                                     UserId,
                             cast(cuj.company_id as bigint) AS                                     CompanyId,
                         cast(ts.SlotsCount as bigint) as SlotsCount,
                         case when cuj.vip is null then false else cuj.vip end vip,
                         u.is_vip       as                                     userVip,

                         case
                             when ts2.EarliestDate isnull then '7777-12-01 21:00:00.000000'
                             else ts2.EarliestDate …
Run Code Online (Sandbox Code Playgroud)

postgresql execution-plan postgresql-performance

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

为什么 COALESCE 会阻止在 varchar 上使用索引,但不会阻止在文本列上使用索引?

想象一个视图,其中包含来自两个不同表的COALESCEvarchar列。

底层证券varchars在两个表中都有索引。

在 Postgres 11.6 中,根据结果过滤此视图COALESCE不使用索引,而是进行表扫描。

但是,如果我将列更改为text,在同一列上过滤完全相同的视图,则索引将按您的预期使用。

例子

假设我有一个一些标识符随时间变化的测量值表。还有一个几乎相同的表,其中包含估计值:

CREATE TABLE measured (
  id int,
  ts timestamp,
  identifier character varying,
  measured_value int
);
CREATE INDEX ON measured(identifier);

CREATE TABLE estimated (
  id int,
  ts timestamp,
  identifier character varying,
  estimated_value int
);
CREATE INDEX ON estimated(identifier);
Run Code Online (Sandbox Code Playgroud)

每个表有 100 万行数据:

INSERT INTO measured
SELECT
    generate_series(1, 1000000),
    to_timestamp((random() * 100000)::int),
    left(md5(random()::text), 2),
    random() * 10;

INSERT INTO estimated
SELECT
    generate_series(1, 1000000),
    to_timestamp((random() * …
Run Code Online (Sandbox Code Playgroud)

postgresql varchar execution-plan index-tuning postgresql-performance

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

优化匹配数组前 N 项的查询

我现在正在使用充满国际象棋游戏数据的 Postgres 数据库,其中每个游戏都是“记录”表中的一行。玩家的动作和这些动作的(可选)计算机评估都有自己的列并存储为数组。

我编写了一个查询来检索指定的开局动作序列的所有评估。(你可能认为计算机的评估会是一致的 - 但事实并非如此。)开局序列的长度是任意的 - 可以是一步,也可以是三十步。

下面是一个示例查询,它查找以相同的十步开局序列开始的所有游戏,然后对于每个带有评估的游戏,返回计算机对游戏中该点的评估 -

SELECT evaluation[10]
FROM records
WHERE moves[1:10]::text[] = ARRAY['b4', 'e5', 'Bb2', 'd6', 'Nf3', 'Nf6', 'g3', 'Bg4', 'Bg2', 'h5']::text[]
AND evaluation IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)

我不确定它是否相关,但移动数据始终是 2-6 个字符的字母数字字符串,并且计算机评估大部分是小数(正数和负数),但确实包括偶尔的特殊字符(强制将死者有一个 octothorpe前缀)。

这是表描述的相关片段 -

     Column      |              Type              | 
-----------------+--------------------------------+-
 id              | bigint                         | 
 moves           | character varying(255)[]       |  
 evaluation      | character varying(255)[]       | 
    "records_pkey" PRIMARY KEY, btree (id)
Access method: heap
Run Code Online (Sandbox Code Playgroud)

这是来自 EXPLAIN ANALYZE 的查询计划:

 Gather  (cost=1000.00..736354.70 rows=905 width=516) (actual time=28251.267..28253.139 rows=0 loops=1)
   Workers Planned: 2 …
Run Code Online (Sandbox Code Playgroud)

postgresql index optimization array postgresql-performance

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

PostgreSQL 忽略索引,运行 seq 扫描

我的表包含列的索引total_balance

\d balances_snapshots
                                          Table "public.balances_snapshots"
    Column     |            Type             | Collation | Nullable |                    Default
---------------+-----------------------------+-----------+----------+------------------------------------------------
 user_id       | integer                     |           |          |
 asset_id      | text                        |           |          |
 timestamp     | timestamp without time zone |           |          | now()
 total_balance | numeric                     |           | not null |
 id            | integer                     |           | not null | nextval('balances_snapshots_id_seq'::regclass)
Indexes:
    "balances_snapshots_pkey" PRIMARY KEY, btree (id)
    "balances_snapshots_asset_id_idx" btree (asset_id)
    "balances_snapshots_timestamp_idx" btree ("timestamp")
    "balances_snapshots_user_id_idx" btree (user_id)
    "balances_total_balance_idx" btree (total_balance)
Foreign-key constraints:
    "balances_snapshots_asset_id_fkey" FOREIGN KEY (asset_id) …
Run Code Online (Sandbox Code Playgroud)

postgresql index datatypes postgresql-performance

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

数组字段上的 btree 索引实际上有什么作用吗?

在PG中你可以创建一个像这样的表

CREATE TABLE foo (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid (),
  name text NOT NULL,
  things text[] NOT NULL DEFAULT ARRAY[] ::text[]
)
Run Code Online (Sandbox Code Playgroud)

以及相关索引

CREATE INDEX foo_text ON foo USING btree (name, things);
Run Code Online (Sandbox Code Playgroud)

但很难找到有关其作用的信息。我继承了一个像这样的表(数亿行,尽管这个数组几乎总是有 0 或 1 个条目),并且索引确实在 pg_stat_all_indexes 中偶尔命中,所以至少在某些情况下可以发生了,但我也注意到,相对于其他索引,该索引占用了大量空间,并且清理速度要慢得多。 PG 中数组字段的索引有意义吗?btree

如果目标是能够找到things包含所提供的一个或多个值的行,是否有更好的方案?(假设我们此时无法将其正确规范化为它自己的表。)

我们期望查询会命中该索引,如下所示

SELECT id FROM foo
WHERE name = $1
AND $2::text = ANY(things)
Run Code Online (Sandbox Code Playgroud)
SELECT id FROM FOO
WHERE name = $1
AND things @> $2::text[]
Run Code Online (Sandbox Code Playgroud)

postgresql index array postgresql-performance

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