Gee*_*ock 5 postgresql performance postgresql-performance
这是一个关于 Postgres (v10) 的内部工作原理和性能的问题。
给定一个表 ,在和列github_repos
上具有多列唯一索引,下面的两个批量更新插入操作之间是否存在任何性能差异(或其他需要注意的问题)?不同之处在于,在第一个查询中,和列包含在 UPDATE 中,而在第二个查询中则不包含。由于 UPDATE 在冲突时运行,因此和的更新值将与旧值相同,但这些列包含在 UPDATE 中,因为我正在使用的底层库就是这样设计的。我想知道按原样使用是否安全,或者我是否应该在更新中明确排除这些列。org_id
github_id
org_id
github_id
org_id
github_id
查询#1:
INSERT INTO "github_repos" ("org_id","github_id","name")
VALUES (1,1,'foo')
ON CONFLICT (org_id, github_id)
DO UPDATE SET "org_id"=EXCLUDED."org_id","github_id"=EXCLUDED."github_id","name"=EXCLUDED."name"
RETURNING "id"
Run Code Online (Sandbox Code Playgroud)
查询#2:
INSERT INTO "github_repos" ("org_id","github_id","name")
VALUES (1,1,'foo')
ON CONFLICT (org_id, github_id)
DO UPDATE SET "name"=EXCLUDED."name"
RETURNING "id"
Run Code Online (Sandbox Code Playgroud)
github_repos
桌子:
Column | Type | Collation | Nullable
-------------------+-------------------+-----------+----------+
id | bigint | | not null |
org_id | bigint | | not null |
github_id | bigint | | not null |
name | character varying | | not null |
Indexes:
"github_repos_pkey" PRIMARY KEY, btree (id)
"unique_repos" UNIQUE, btree (org_id, github_id)
Run Code Online (Sandbox Code Playgroud)
从性能角度来看,这似乎没有什么区别,假设您没有仅在更新某些列时运行的触发器。
整行都被更新,或者更具体地说是 Postgres 特有的(Postgres 没有就地更新),新的元组将被插入,旧的元组将被标记为 dead 。从这一点来看,实际更改是否仅发生在一列、所有列或两者都没有发生并不重要。您可以检查 n_tup_upd 和 n_dead_tup 列的值pg_stat_all_tables
- 它们在每次更新后都会增加。n_dead_tup
执行后最终会重置vacuum
。
唯一可能受到负面影响的是热更新(如果索引列不更改值,则不会有新的索引元组)。HOT 更新在很多地方都有解释,我认为最好的一个是http://www.interdb.jp/pg/pgsql07.html。
测试 HOT 更新(使用 Postgres 9.6、10.4 和 10.5 完成)
--- setup
-- useful extension for checking data and index pages
create extension pageinspect;
-- dummy table (varchar is used instead of text just to avoid any complication related to TOAST )
create table test_update(test_update_id int not null , some_data varchar(50),constraint test_update_pkey primary key (test_update_id) );
-- insert 2 rows
insert into test_update (test_update_id, some_data) values (1, 'test1');
insert into test_update (test_update_id, some_data) values (2, 'test2');
--check table stats :
select relname ,n_tup_upd, n_dead_tup , n_tup_hot_upd from pg_stat_all_tables where relname ='test_update';
--(all zeroes)
-- check #rows in index :
select * from bt_page_items('test_update_pkey',1) ;
-- 2 rows
----------------------------------------------
-- Test 1 . perform dummy update :
update test_update set test_update_id = test_update_id , some_data = some_data;
-- check tables stats again,
--n_tup_upd = n_dead_tup = n_tup_hot_upd = 2
-- check index page again, results are the same - 2 rows
-- Test 2 . real update non-key column , and dummy update of key column :
update test_update set test_update_id = test_update_id , some_data = some_data||'_new';
-- check tables stats again,
--n_tup_upd = n_dead_tup = n_tup_hot_upd = 4
-- check index page again, results are the same - 2 rows
-- Test 3 . real update non-key column , key column is not in the statement:
update test_update set some_data = some_data||'_new_2';
-- check tables stats again,
--n_tup_upd = n_dead_tup = n_tup_hot_upd = 6
-- check index page again, results are the same - 2 rows
-- Test 4. Now do real update of key column :
update test_update set test_update_id = test_update_id+2;
-- check tables stats again,
--n_tup_upd = n_dead_tup = 8, n_tup_hot_upd = 6 (no HOT update this time)
-- check index page again, now we see 4 rows
Run Code Online (Sandbox Code Playgroud)
看来 Postgres 足够聪明,可以识别索引列未更改的情况,并执行热更新;因此,从性能角度来看,更新语句中包含或不包含键列没有区别。唯一重要的是实际价值是否改变。当然,这种行为仅限于 B-Tree 索引。
归档时间: |
|
查看次数: |
4316 次 |
最近记录: |