Database 利用postgres中的top-N堆对顺序的理解

Database 利用postgres中的top-N堆对顺序的理解,database,performance,postgresql,Database,Performance,Postgresql,在没有索引的理论场景中,带有限制的order by必须扫描所有数据,然后应用order by,然后仅应用限制,因为我们只能在排序后获得前10行作为示例 但博士后在这里更聪明一点,下面的计划说明了这一点 限价订货 learning=# explain (analyze,buffers) select * from temp order by userid limit 10; QUER

在没有索引的理论场景中,带有限制的order by必须扫描所有数据,然后应用order by,然后仅应用限制,因为我们只能在排序后获得前10行作为示例

但博士后在这里更聪明一点,下面的计划说明了这一点

限价订货

learning=# explain (analyze,buffers) select * from temp order by userid limit 10;
                                                          QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=81745.51..81745.54 rows=10 width=41) (actual time=2064.275..2064.278 rows=10 loops=1)
   Buffers: shared hit=13 read=18644
   ->  Sort  (cost=81745.51..86735.41 rows=1995958 width=41) (actual time=2064.273..2064.274 rows=10 loops=1)
         Sort Key: userid
         Sort Method: top-N heapsort  Memory: 25kB
         Buffers: shared hit=13 read=18644
         ->  Seq Scan on temp  (cost=0.00..38613.58 rows=1995958 width=41) (actual time=35.053..1652.660 rows=1995958 loops=1)
               Buffers: shared hit=10 read=18644
 Planning time: 0.167 ms
 Execution time: 2064.335 ms
(10 rows)
无限量订购

learning=# explain (analyze,buffers) select * from temp order by userid;
                                                      QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------
 Sort  (cost=308877.61..313867.51 rows=1995958 width=41) (actual time=2685.680..3293.698 rows=1995958 loops=1)
   Sort Key: userid
   Sort Method: external merge  Disk: 99504kB
   Buffers: shared hit=42 read=18612, temp read=12440 written=12440
   ->  Seq Scan on temp  (cost=0.00..38613.58 rows=1995958 width=41) (actual time=0.069..286.556 rows=1995958 loops=1)
         Buffers: shared hit=42 read=18612
 Planning time: 0.066 ms
 Execution time: 3540.545 ms
(8 rows)
我的假设是,postgres使用了一种称为heap sort的算法,这是众所周知的,并且在获得前N个限制行时停止


从视觉上看,我无法理解这是如何工作的?有谁能解释一下这一点。我上面的假设正确吗?

我还没有深入阅读源代码,但据我所知,它保持着一个大小有限的堆

它按顺序使用输入值。在将堆填充到目标元组数之后,它开始检查每个新值,以查看它是否大于所有当前值、小于所有当前值或是否适合堆

如果它大于所有当前值(假设为ASC sort),那么它将被丢弃,因为我们已经有了足够低的值

如果它小于所有当前值或某些当前值,则会将其插入堆中的适当点,所有内容向下移动1,并将最后一个条目从堆中删除


请参见git master中第行的src/backend/utils/sort/tuplesort.c,case TSS_BOUNDED:in puttuple_common。

您链接到的可视化只是一个正在执行的heapsort。堆数据结构是一个二叉树,其属性是每个节点中的值大于或小于其子节点中的值。堆可以存储在数组中,这就是可视化显示的内容


堆可以用作有效的优先级队列。因为它只是部分排序,所以作为优先级队列使用比排序列表或类似的东西更便宜。这可能就是Postgres所做的:如果您从一个表中选择N个最大值,Postgres将保留一个优先级队列,该队列由迄今为止看到的N个最大值组成的堆实现,最小值放在第一位,即堆的顶部。如果新值甚至小于优先级队列的第一项,则可以丢弃新值。如果较大,请从优先级队列中删除第一个值并插入新值。

PostgreSQL为此使用top-N排序堆。在对这样的查询执行解释分析时,您可以看到这一点。 如果没有索引,则无法避免完整表扫描。但是,top-N heapsort避免为所有行分配内存,因为 只关心前10个

例如,我有一个600万条目的表,并要求按未索引的列列出前10行。应用了限制10,它告诉我:

      Sort Method: top-N heapsort  Memory: 25kB
      Without:
      Sort Method: quicksort  Memory: (some value)kB
因此,如果Postgres必须存储所有已排序的600万行,那么它将需要大量MB的工作内存。如果你看表演的话,它就在下面 这将导致it将大量临时文件写入磁盘:

      Sort Method: external merge  Disk: 99504kB

为了使用快速记忆扫描,您必须增加工时_mem参数

,这非常有趣。必须提高我的C技能。谢谢: