Postgresql 选择ID包含在另一个表中的记录

Postgresql 选择ID包含在另一个表中的记录,postgresql,Postgresql,到目前为止,这似乎完全没有问题。接下来,我想使用另一个表中的ID,而不是在查询中指定它们 vit=# select count(*) from evtags; count --------- 4496914 vit=# explain select tag from evtags where evid in (1002, 1023); QUERY PLAN

到目前为止,这似乎完全没有问题。接下来,我想使用另一个表中的ID,而不是在查询中指定它们

vit=# select count(*) from evtags;
  count  
---------
 4496914

vit=# explain select tag from evtags where evid in (1002, 1023);
                              QUERY PLAN                                    
---------------------------------------------------------------------------------
 Index Only Scan using evtags_pkey on evtags  (cost=0.00..15.64 rows=12 width=7)
   Index Cond: (evid = ANY ('{1002,1023}'::integer[]))
我们走吧

vit=# select count(*) from zzz;
 count 
-------
 49738
为什么要在更大的表上进行索引扫描?正确的方法是什么

编辑

我重新创建了我的
zzz
表,由于某些原因,现在它更好了:

vit=# explain select tag from evtags where evid in (select evid from zzz);
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Hash Semi Join  (cost=1535.11..142452.47 rows=291712 width=7)
   Hash Cond: (evtags.evid = zzz.evid)
   ->  Seq Scan on evtags  (cost=0.00..69283.14 rows=4496914 width=11)
   ->  Hash  (cost=718.38..718.38 rows=49738 width=4)
         ->  Seq Scan on zzz  (cost=0.00..718.38 rows=49738 width=4)
但在几次执行之后,它变为

vit=# explain analyze select tag from evtags where evid in (select evid from zzz);
                                                         QUERY PLAN                                                             
------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=708.00..2699.17 rows=2248457 width=7) (actual time=28.935..805.923 rows=244353 loops=1)
   ->  HashAggregate  (cost=708.00..710.00 rows=200 width=4) (actual time=28.893..54.461 rows=38822 loops=1)
         ->  Seq Scan on zzz  (cost=0.00..601.80 rows=42480 width=4) (actual time=0.032..10.985 rows=40000 loops=1)
   ->  Index Only Scan using evtags_pkey on evtags  (cost=0.00..9.89 rows=6 width=11) (actual time=0.015..0.017 rows=6 loops=38822)
         Index Cond: (evid = zzz.evid)
         Heap Fetches: 0
 Total runtime: 825.651 ms
…这实际上比较慢。有没有办法提示它一个“正确”的执行计划


这些操作的要点是,我希望对数据的子集执行大量查询,并希望使用单独的临时表来保存我要处理的记录的ID。

内部联接更有可能实现良好的计划:

vit=# explain analyze select tag from evtags where evid in (select evid from zzz);
                                                                    QUERY PLAN                                                                     
---------------------------------------------------------------------------------------------------------------------------------------------------
 Merge Semi Join  (cost=4184.11..127258.48 rows=235512 width=7) (actual time=38.269..1461.755 rows=244353 loops=1)
   Merge Cond: (evtags.evid = zzz.evid)
   ->  Index Only Scan using evtags_pkey on evtags  (cost=0.00..136736.89 rows=4496914 width=11) (actual time=0.038..899.647 rows=3630070 loops=1)
         Heap Fetches: 0
   ->  Materialize  (cost=4184.04..4384.04 rows=40000 width=4) (actual time=38.212..61.038 rows=40000 loops=1)
         ->  Sort  (cost=4184.04..4284.04 rows=40000 width=4) (actual time=38.208..51.104 rows=40000 loops=1)
               Sort Key: zzz.evid
               Sort Method: external sort  Disk: 552kB
               ->  Seq Scan on zzz  (cost=0.00..577.00 rows=40000 width=4) (actual time=0.018..8.833 rows=40000 loops=1)
 Total runtime: 1484.293 ms
或者这个:

select e.tag
from
    evtags e
    inner join
    zzz z using (evid)

正如注释中所指出的,运行
分析evtags;分析zzz

您的表是否有主键/外键(没有索引扫描,可能有两个)您是否有有效的统计信息?请添加表定义,包括PK/FK和/或索引。顺便说一句:如果结果集很小并且需要大多数元组,这种计划是正常的。BTW2:
explain analyze
将向您显示估计和测量的计数/数字。在重新创建
zzz
表后,您是否运行了
vacuum analyze
?(它将更新统计数据)另外:“外部”表需要大约50%的行,索引可能无助于找到它们(因为基本上每个磁盘页都需要)。您可以尝试将random_page_cost降至1.5(或将work_mem降至较小的值)以强制执行索引扫描,但这仅在需要获取的行/页较少时才有意义。顺便问一下:zzz表格有PK/FK/索引吗?请添加表定义,包括PK/FK/索引。
select e.tag
from evtags e
where exists (
    select 1
    from zzz
    where evid = e.evid
)