我正在对一个包含 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) 我在 PosgreSQL 中的递归查询性能很差。
psql --version
psql (PostgreSQL) 10.7 (Ubuntu 10.7-1.pgdg16.04+1)
Run Code Online (Sandbox Code Playgroud)
这个想法是拥有树状的评论结构。所以什么时候parent_id是NULL父评论,什么时候是整数,什么时候是回复。
我的评论表()的表结构如下\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) 我在 Web API 中有一个 JDBC 连接池,它经常向 RDS 实例发出请求。每个请求都是针对长时间运行的 SQL 查询,其中 PG 决定不使用索引,因为要返回的数据量非常大。
我注意到其中一些长时间运行的查询只是停留在 state idle in transaction。当在表中查找pid这些进程时pg_locks,它们有 152 行。带模式AccessShareLock。
该表的目的是永远不会更新——它充当时间表中的一个点。所以我认为不需要idle transactionor accesssharelock。我是否可以关闭这些功能,以便我的查询运行得更快并且不会因为AccessShareLock?
我正在运行一个查询,例如
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)
这相当快。
现在我们将 …
我有一个数据库,其中有一列名为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 month(1 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) 我这里有一个非常奇怪的问题。我们的搜索查询接收多个参数并通过不同表中的多个联接进行搜索。查询在我们运行的前几次运行良好,然后有时会严重减慢,例如:从 200 毫秒到 15000/20000 毫秒。在同一个查询上。
最初我认为这是后端 ORM 问题,但在彻底检查并打开慢速查询日志、打开 auto_explain 功能后,我意识到查询计划在几次调用后发生了变化。我们在后端放置一个循环,在同一线程上多次执行查询(用于测试),我发现几乎总是在执行 8 次后数据库开始记录慢速查询。最后结果是查询计划发生了变化。最重要的变化是(我认为)TimeSlots 表上的变化,从 seq 扫描到位图索引扫描,它估计的行数比表中的行数少得多。估计:566 实际:100 000 左右。
我之前尝试过的事情:
这是选择语句:
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) 想象一个视图,其中包含来自两个不同表的COALESCE两varchar列。
底层证券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
我现在正在使用充满国际象棋游戏数据的 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) 我的表包含列的索引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) 在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 ×10
index ×4
performance ×3
array ×2
index-tuning ×2
datatypes ×1
optimization ×1
update ×1
upsert ×1
varchar ×1