在小表和大表之间的内部连接期间,索引被忽略

Posted

技术标签:

【中文标题】在小表和大表之间的内部连接期间,索引被忽略【英文标题】:During the Inner Join between a small and a large table the index is ignored 【发布时间】:2019-11-19 19:33:01 【问题描述】:

我在 Postgresql 中有两个简单的表,第一个有 170 万

CREATE TABLE f_occ(
id_data integer ,
dur integer
);

第二个表有 365

CREATE TABLE d_data(
id_data serial ,
full_data date , 
month SMALLINT ,
);

为了优化两个表之间的连接,我尝试在 id_data 上创建哈希索引,但这完全被忽略了。为什么会发生这种情况,如何优化查询?当我在表 d_data 的 where 中插入条件时也会发生这种情况。

CREATE INDEX f_occ_id_data ON public.f_occ USING hash (id_data)
EXPLAIN ANALYZE
SELECT d.month, s.dur
FROM d_data d, f_occ s
WHERE d.id_data = s.id_data;

"Hash Join  (cost=10.21..34133.23 rows=1705429 width=6) (actual time=1.479..9158.424 rows=1705429 loops=1)"
"  Hash Cond: (s.id_data = d.id_data)"
"  ->  Seq Scan on f_occ s  (cost=0.00..29594.29 rows=1705429 width=8) (actual time=0.096..2992.577 rows=1705429 loops=1)"
"  ->  Hash  (cost=5.65..5.65 rows=365 width=6) (actual time=1.352..1.353 rows=365 loops=1)"
"        Buckets: 1024  Batches: 1  Memory Usage: 23kB"
"        ->  Seq Scan on d_data d  (cost=0.00..5.65 rows=365 width=6) (actual time=0.030..0.656 rows=365 loops=1)"
"Planning Time: 0.919 ms"
"Execution Time 11727.436 ms"

【问题讨论】:

连接不会减少来自f_occ 的行数,因此对该表的表进行 Seq Scan 是有意义的(毕竟,您正在从该表中检索所有行)。如果只有来自f_occ 的一小部分行将从连接中返回,则可能会使用该索引。 但如果我尝试插入 d.month = 1 之类的 where 条件,则索引将继续被忽略,该索引仅在我对 full_data 设置条件的情况下使用,例如 d.full_data = '2017-02-02' 那么 where 条件没有删除足够的行以使索引有用 【参考方案1】:

如果表很小,一些查询优化器更喜欢使用对内存中表的完全访问来避免索引访问。

另一个元素是在您的情况下使用旧的隐式连接语法假设主/前导表,基于您似乎建议查询优化器将 f_occ 用作主/前导表的位置。尝试更改以 d_data 为主表的表的顺序,并采用基于显式连接语法的 JOIN 和 ON 子句:

SELECT d.month, s.dur
FROM d_data d
INNER JOIN  f_occ s  ON  d.id_data = s.id_data;

为了获得更好的性能,您应该使用复合索引,允许查询优化器直接通过索引解析与 f_occ 表相关的所有查询信息。

 CREATE INDEX f_occ_id_data ON public.f_occ USING hash (id_data, dur)

【讨论】:

从隐式连接更改为显式连接不会产生影响。并且内部连接的表顺序也没有区别。

以上是关于在小表和大表之间的内部连接期间,索引被忽略的主要内容,如果未能解决你的问题,请参考以下文章

hive join 优化 --小表join大表

hive大表和小表MapJoin关联查询优化

表连接中的驱动表与被驱动表

mysql join 谁是驱动表

小表内连接大表,如何加快

MySQL表连接之驱动表与被驱动表