【发布时间】: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经常扼杀索引的使用。我能说什么?习惯它。您了解一种解决方法,即使用单独的子查询。
标签: sql database postgresql performance indexing