如何让 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_id
和 block_number
上的过滤器,那么查询将在合理的时间内执行。由于这个新的约束较少的查询正在运行,如果索引不存在并且它只是一个额外的过滤器,我希望即使是原始的约束更多的查询也能运行。如何在不删除索引的情况下实现?
您可以通过对索引列进行一些虚拟运算来禁用索引。
...AND "chaindata_tokentransfer"."chain_id" + 0 = 1...
如果您将其投入生产,请确保添加代码注释以说明您为什么做这种奇怪的事情。
我很好奇为什么它选择使用该索引,尽管显然知道它有多么糟糕。如果您显示禁用索引的查询计划,也许我们可以解决这个问题。
如果虚拟算法不起作用,你可以做的是启动一个事务,删除索引,执行查询(或者只是它的解释),然后回滚删除。这可能不是你想在生产中经常做的事情(特别是因为 table 从索引被删除到回滚时将被锁定。也因为你可能会不小心提交!)但是获得计划可能是值得做的一次。
我有以下查询:
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_id
和 block_number
上的过滤器,那么查询将在合理的时间内执行。由于这个新的约束较少的查询正在运行,如果索引不存在并且它只是一个额外的过滤器,我希望即使是原始的约束更多的查询也能运行。如何在不删除索引的情况下实现?
您可以通过对索引列进行一些虚拟运算来禁用索引。
...AND "chaindata_tokentransfer"."chain_id" + 0 = 1...
如果您将其投入生产,请确保添加代码注释以说明您为什么做这种奇怪的事情。
我很好奇为什么它选择使用该索引,尽管显然知道它有多么糟糕。如果您显示禁用索引的查询计划,也许我们可以解决这个问题。
如果虚拟算法不起作用,你可以做的是启动一个事务,删除索引,执行查询(或者只是它的解释),然后回滚删除。这可能不是你想在生产中经常做的事情(特别是因为 table 从索引被删除到回滚时将被锁定。也因为你可能会不小心提交!)但是获得计划可能是值得做的一次。