在小表和大表之间的内部连接期间,索引被忽略
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)
【讨论】:
从隐式连接更改为显式连接不会产生影响。并且内部连接的表顺序也没有区别。以上是关于在小表和大表之间的内部连接期间,索引被忽略的主要内容,如果未能解决你的问题,请参考以下文章