我需要在 Postgres 中连接 2 个表的多个列。每个表中的列都有不同的类型。
这不是一个如何连接表的问题(这个问题已经被问过并回答了好几次),而是如何在充分利用索引的情况下高效地连接它们。这些表有数百万条记录。
如果我要设计一个新表,其中的列始终具有
int
值,但我需要 JOIN
到另一个具有 text
值的现有旧表,什么会带来更好的性能:
int
并牺牲 JOIN
的性能,或 text
以避免强制转换并具有 JOIN
“直接”,并牺牲列的大小和索引的性能(我假设 int
上的索引比索引text
)。CREATE TABLE table_new
(
id1 int NOT NULL,
id2 int NOT NULL,
-- other columns
);
CREATE INDEX idx_new_id ON table_new (id1, id2);
CREATE TABLE table_old
(
id1 text NOT NULL,
id2 text NOT NULL,
-- other columns
);
CREATE INDEX idx_old_id ON table_old (id1, id2);
我需要在
table_old
和 table_new
上加入 id1
和 id2
。我知道我可以使用各种形式的强制转换(如所述,例如 如果列类型不同,则在 postgresql 中加入两个表)。
我实际上需要实现的目标相当于
SELECT * FROM table_old
JOIN table_new
ON table_old.id1 = table_new.id1 AND table_old.id2 = table_new.id2;
但是,如何使用索引,或者如何创建索引以使联接高效?
我担心在
id1
和id2
之间任何形式的铸造int
和text
都会破坏性能。
为了避免 XY 问题,这里有更广泛的背景:
table_old
是一个遗留表,我不允许更改。table_new
是我正在设计的新桌子。table_new
中,列 id1
和 id2
always 包含 int
值,所以我想让表及其索引尽可能小且尽可能快,因此我将它们设计为 int
。JOIN
具有不同类型列的表,我也可以接受列为text
作为解决方案。JOIN
。功能索引来救援!
CREATE TEMP TABLE t_old (tid text PRIMARY KEY);
CREATE TEMP TABLE t_new (iid int NOT NULL);
CREATE INDEX t_old_int_idx ON t_old ((tid::int));
CREATE INDEX t_new_int_idx ON t_new (iid);
INSERT INTO t_old SELECT i::text FROM generate_series(1,99999) i;
INSERT INTO t_new VALUES (10),(20),(30);
ANALYSE t_old;
ANALYSE t_new;
EXPLAIN ANALYSE SELECT t_new.*, t_old.* FROM t_new JOIN t_old ON t_new.iid = t_old.tid::int;
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Merge Join (cost=1.69..2.51 rows=3 width=9) (actual time=0.063..0.082 rows=3 loops=1) │
│ Merge Cond: ((t_old.tid)::integer = t_new.iid) │
│ -> Index Scan using t_old_int_idx on t_old (cost=0.29..3050.28 rows=99999 width=5) (actual time=0.016..0.028 rows=31 loops=1) │
│ -> Sort (cost=1.05..1.06 rows=3 width=4) (actual time=0.021..0.022 rows=3 loops=1) │
│ Sort Key: t_new.iid │
│ Sort Method: quicksort Memory: 25kB │
│ -> Seq Scan on t_new (cost=0.00..1.03 rows=3 width=4) (actual time=0.009..0.010 rows=3 loops=1) │
│ Planning Time: 0.485 ms │
│ Execution Time: 0.127 ms │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
If not all the values in your old table are in fact valid integers you might need to make your functional index partial too.