如何让 postgres 不使用特定的索引?

How to make postgres not use a particular index?

我有以下查询:

devapp=>  Explain SELECT DISTINCT "chaindata_tokentransfer"."emitting_contract" FROM "chaindata_tokentransfer" WHERE (("chaindata_tokentransfer"."to_addr" = 100 OR "chaindata_tokentransfer"."from_addr" = 100) AND "chaindata_tokentransfer"."chain_id" = 1 AND "chaindata_tokentransfer"."block_number" >= 10000);
                                                                          QUERY PLAN                                                                          
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 Unique  (cost=29062023.48..29062321.43 rows=8870 width=4)
   ->  Sort  (cost=29062023.48..29062172.45 rows=59591 width=4)
         Sort Key: emitting_contract
         ->  Bitmap Heap Scan on chaindata_tokentransfer  (cost=28822428.06..29057297.07 rows=59591 width=4)
               Recheck Cond: (((to_addr = 100) OR (from_addr = 100)) AND (chain_id = 1) AND (block_number >= 10000))
               ->  BitmapAnd  (cost=28822428.06..28822428.06 rows=59591 width=0)
                     ->  BitmapOr  (cost=4209.94..4209.94 rows=351330 width=0)
                           ->  Bitmap Index Scan on chaindata_tokentransfer_to_addr_284dc4bc  (cost=0.00..1800.73 rows=150953 width=0)
                                 Index Cond: (to_addr = 100)
                           ->  Bitmap Index Scan on chaindata_tokentransfer_from_addr_ef8ecd8c  (cost=0.00..2379.41 rows=200377 width=0)
                                 Index Cond: (from_addr = 100)
                     ->  Bitmap Index Scan on chaindata_tokentransfer_chain_id_block_number_tx_eeeac2a4_idx  (cost=0.00..28818202.98 rows=1315431027 width=0)
                           Index Cond: ((chain_id = 1) AND (block_number >= 10000))
(13 rows)

如您所见,chaindata_tokentransfer_chain_id_block_number_tx_eeeac2a4_idx 上最后一次索引扫描的成本非常高。查询超时。如果我从查询中删除 chain_idblock_number 上的过滤器,那么查询将在合理的时间内执行。由于这个新的约束较少的查询正在运行,如果索引不存在并且它只是一个额外的过滤器,我希望即使是原始的约束更多的查询也能运行。如何在不删除索引的情况下实现?

您可以通过对索引列进行一些虚拟运算来禁用索引。

 ...AND "chaindata_tokentransfer"."chain_id" + 0 = 1...

如果您将其投入生产,请确保添加代码注释以说明您为什么做这种奇怪的事情。

我很好奇为什么它选择使用该索引,尽管显然知道它有多么糟糕。如果您显示禁用索引的查询计划,也许我们可以解决这个问题。

如果虚拟算法不起作用,你可以做的是启动一个事务,删除索引,执行查询(或者只是它的解释),然后回滚删除。这可能不是你想在生产中经常做的事情(特别是因为 table 从索引被删除到回滚时将被锁定。也因为你可能会不小心提交!)但是获得计划可能是值得做的一次。