当我使用“或”条件时,为啥我的查询使用过滤而不是索引条件?
Posted
技术标签:
【中文标题】当我使用“或”条件时,为啥我的查询使用过滤而不是索引条件?【英文标题】:Why is my query uses filtering instead of index cond when I use an `OR` condition?当我使用“或”条件时,为什么我的查询使用过滤而不是索引条件? 【发布时间】:2021-11-12 18:50:23 【问题描述】:我在 PostgreSQL 中有一个 transactions
表,其中 block_height
和 index
作为 BIGINT
值。这两个值用于确定此表中事务的顺序。
因此,如果我想从该表中查询给定 block_height
和 index
之后的事务,我必须将其置于条件
block_height
中,则检查它们的index
的顺序
否则比较他们的block_height
例如,如果我想获得 10 个在 block_height 100000
和 index 5
之后发生的事务:
SELECT * FROM transactions
WHERE (
(block_height = 10000 AND index > 5)
OR (block_height > 10000)
)
ORDER BY block_height, index ASC
LIMIT 10
但是我发现这个查询非常慢,对于一个有 5000 万行的表,它最多需要 60 秒。
但是,如果我拆分条件并像这样单独运行它们:
SELECT * FROM transactions
WHERE block_height = 10000 AND index > 5
ORDER BY block_height, index ASC
LIMIT 10
和
SELECT * FROM transactions
WHERE block_height > 10000
ORDER BY block_height, index ASC
LIMIT 10
两个查询最多在同一张表上使用200ms
!执行两个查询然后UNION
最终结果比在条件中添加OR
要快得多。
这是慢查询(OR-ed 条件)的查询计划的一部分:
-> Nested Loop (cost=0.98..11689726.68 rows=68631 width=73) (actual time=10230.480..10234.289 rows=10 loops=1)
-> Index Scan using src_transactions_block_height_index on src_transactions (cost=0.56..3592792.96 rows=16855334 width=73) (actual time=10215.698..10219.004 rows=1364 loops=1)
Filter: (((block_height = $1) AND (index > $2)) OR (block_height > $3))
Rows Removed by Filter: 2728151
这是快速查询的查询计划:
-> Nested Loop (cost=0.85..52.62 rows=1 width=73) (actual time=0.014..0.014 rows=0 loops=1)
-> Index Scan using src_transactions_block_height_index on src_transactions (cost=0.43..22.22 rows=5 width=73) (actual time=0.014..0.014 rows=0 loops=1)
Index Cond: ((block_height = $1) AND (index > $2))
我认为主要区别在于查询计划之间使用Filter
而不是Index Cond
。
有没有什么方法可以在不使用UNION
解决方法的情况下以高效的方式执行此查询?
【问题讨论】:
or
经常扼杀索引的使用。我能说什么?习惯它。您了解一种解决方法,即使用单独的子查询。
【参考方案1】:
block_height 与您知道恰好相等的两个不同参数进行比较的事实可能是一个问题。如果您两次使用 $1,而不是 $1 和 $3,会怎样?
但更好的是,尝试一个元组比较
WHERE (block_height, index) > (10000, 5)
使用(block_height, index)
上的两列索引可以加快速度。
【讨论】:
完美!非常感谢,我不知道你可以进行元组比较。使用这个比较,我的查询在同一张表上运行只需 190 毫秒。以上是关于当我使用“或”条件时,为啥我的查询使用过滤而不是索引条件?的主要内容,如果未能解决你的问题,请参考以下文章
为啥当我使用 IIF 时,我的表中的某些行而不是其他行的日期转换失败
为啥当我使用 Perl 的 REST::Client 发送 POST 请求,而不是使用 Perl 的 LWP::UserAgent 或 Python 时,我得到“405: Method Not All