postgresql LIMIT为1000倍的小结果查询比大于100行的查询慢

0tdrvxhp  于 2023-02-08  发布在  PostgreSQL
关注(0)|答案(3)|浏览(267)

我正在调试一个查询,它返回的记录越多,运行速度就越快,但使用小LIMIT(ie 10)时,返回越少(即〈10行),性能就会严重下降(慢10倍以上)。
示例:
快速查询,100万行中有5个结果-无限制

SELECT *
FROM transaction_internal_by_addresses
WHERE address = 'foo'
ORDER BY block_number desc;

解释:

Sort  (cost=7733.14..7749.31 rows=6468 width=126) (actual time=0.030..0.031 rows=5 loops=1)
"  Output: address, block_number, log_index, transaction_hash"
  Sort Key: transaction_internal_by_addresses.block_number
  Sort Method: quicksort  Memory: 26kB
  Buffers: shared hit=10
  ->  Index Scan using transaction_internal_by_addresses_pkey on public.transaction_internal_by_addresses  (cost=0.69..7323.75 rows=6468 width=126) (actual time=0.018..0.021 rows=5 loops=1)
"        Output: address, block_number, log_index, transaction_hash"
        Index Cond: (transaction_internal_by_addresses.address = 'foo'::text)
        Buffers: shared hit=10
Query Identifier: -8912211611755432198
Planning Time: 0.051 ms
Execution Time: 0.041 ms

快速查询,100万行中有5个结果:- 上限
一个二个一个一个
查询速度慢:-下限

SELECT *
FROM transaction_internal_by_addresses
WHERE address = 'foo'
ORDER BY block_number desc
LIMIT 10;

解释结果:

Limit  (cost=1000.63..6133.94 rows=10 width=126) (actual time=10277.845..11861.269 rows=0 loops=1)
"  Output: address, block_number, log_index, transaction_hash"
  Buffers: shared hit=56313576
  ->  Gather Merge  (cost=1000.63..3333036.90 rows=6491 width=126) (actual time=10277.844..11861.266 rows=0 loops=1)
"        Output: address, block_number, log_index, transaction_hash"
        Workers Planned: 4
        Workers Launched: 4
        Buffers: shared hit=56313576
        ->  Parallel Index Scan Backward using transaction_internal_by_address_idx_block_number on public.transaction_internal_by_addresses  (cost=0.57..3331263.70 rows=1623 width=126) (actual time=10256.995..10256.995 rows=0 loops=5)
"              Output: address, block_number, log_index, transaction_hash"
              Filter: (transaction_internal_by_addresses.address = 'foo'::text)
              Rows Removed by Filter: 18485480
              Buffers: shared hit=56313576
              Worker 0:  actual time=10251.822..10251.823 rows=0 loops=1
                Buffers: shared hit=11387166
              Worker 1:  actual time=10250.971..10250.972 rows=0 loops=1
                Buffers: shared hit=10215941
              Worker 2:  actual time=10252.269..10252.269 rows=0 loops=1
                Buffers: shared hit=10191990
              Worker 3:  actual time=10252.513..10252.514 rows=0 loops=1
                Buffers: shared hit=10238279
Query Identifier: 2050754902087402293
Planning Time: 0.081 ms
Execution Time: 11861.297 ms
    • DDL公司**
create table transaction_internal_by_addresses
(
    address          text   not null,
    block_number     bigint,
    log_index        bigint not null,
    transaction_hash text   not null,
    primary key (address, log_index, transaction_hash)
);

alter table transaction_internal_by_addresses
    owner to "icon-worker";

create index transaction_internal_by_address_idx_block_number
    on transaction_internal_by_addresses (block_number);
所以我的问题
  • 我应该只考虑强制查询计划器对address(主键)应用WHERE的方法吗?
  • 正如您在解释中所看到的,行block_number在慢速查询中被扫描,但我不知道为什么。有人能解释一下吗?
  • 这正常吗?似乎数据越多,查询就越困难,而不是像本例中那样相反。

更新

  • 抱歉,A,答复的延迟,B,这个问题中的一些不一致之处。
  • 我更新了解释,清楚地显示了1000倍的性能下降
omhiaaxx

omhiaaxx1#

(address, block_number DESC)上的多列BTREE索引正是查询计划器生成您提到的结果集所需要的。它将随机访问索引到第一个符合条件的行,然后按顺序读取行,直到达到LIMIT。您也可以省略DESC,而不会产生不良影响。

create index address_block_number
on transaction_internal_by_addresses
 (address, block_number DESC);

至于询问查询计划器结果的“为什么”,这通常是一个持久的谜。

ndasle7k

ndasle7k2#

亚毫秒级的差异很难预测,所以你几乎只能看到噪音,以及系统上发生的其他事情所导致的随机微小差异。你最快的查询运行时间为数十微秒,最慢的为一毫秒 -所有这些都低于典型的网络、鼠标点击、屏幕刷新延迟。
1.计划员已经在您的address上应用了where
指数条件:(a_表格.地址= 'foo'::文本)*
1.您是按block_number排序的,所以扫描它是有意义的,而且这也发生在您的所有三个查询中,因为它们都这样做。

  1. here's an online demo也有类似的区别,如果你需要可靠的时间估计,可以使用pgbench多次运行你的查询,并计算出时间的平均值。
    您的第三个查询计划似乎来自针对不同表的不同查询:a_table,与前两个相比:transaction_internal_by_addresses.
    如果你只是想知道为什么这些时间看起来像这样,它在这个层次上几乎是随机的和/或不相关的。如果你因为这些查询的行为而面临某种问题,最好集中精力描述这个问题-查询本身都做同样的事情,它们的执行时间差异可以忽略不计。
tf7tbtn2

tf7tbtn23#

1.我应该只考虑强制查询计划器对地址(主键)应用WHERE的方法吗?

  • 是的,它可以提高性能

1.正如您在解释中所看到的,block_number行在慢速查询中被扫描,但我不知道为什么。有人能解释一下吗?

  • 因为排序键是不同的。请仔细观察:

Sort Key: transaction_internal_by_addresses.block_number DESC
Sort Key: a_table.a_indexed_row DESC
看起来a_table.a_indexed_row的性能较差(例如,列更多,结构更复杂等)
1.这正常吗?似乎数据越多,查询就越困难,而不是像本例中那样相反。

  • 通常更多的查询会花费更多的时间,但是正如我上面提到的,可能a_table.a_indexed_row返回更多的值,拥有更多的列等等。

相关问题