PostgreSQL指南:内幕探索
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.4 执行器如何工作

在单表查询的例子中,执行器从计划树中取出计划节点,按照自底向上的顺序进行处理,并调用节点相应的处理函数。

每个计划节点都有相应的函数,用于执行节点对应的操作。这些函数在 src/backend/executor 目录中。例如,执行顺序扫描的函数(SeqScan)定义在nodeSeqscan.c 中,执行索引扫描的函数(IndexScanNode)定义在nodeIndexScan.c中,SortNode节点对应的排序函数定义在nodeSort.c中,诸如此类。

当然,理解执行器如何工作的最好方式,就是阅读EXPLAIN命令的输出。因为PostgreSQL的EXPLAIN命令几乎就是照着计划树输出的。下面以第3.3.3.1节的例1为例。

    1.testdb=# EXPLAIN SELECT * FROM tbl_1 WHERE id < 300 ORDER BY data;
    2.                              QUERY PLAN
    3.---------------------------------------------------------------
    4. Sort  (cost=182.34..183.09 rows=300 width=8)
    5.   Sort Key: data
    6.   ->  Seq Scan on tbl_1  (cost=0.00..170.00 rows=300 width=8)
    7.          Filter: (id < 300)
    8.(4 rows)

我们可以自底向上阅读EXPLAIN的结果,来看一看执行器是如何工作的。

第6行:首先,执行器通过nodeSeqscan.c中定义的函数执行顺序扫描操作。

第4行:然后,执行器通过nodeSort.c中定义的函数,对顺序扫描的结果进行排序。

临时文件

执行器在处理查询时会使用工作内存和临时缓冲区,两者都在内存中分配。如果查询无法在内存中完成,就会用到临时文件。

使用带有Analyze选项的EXPLAIN,待解释的命令会真正执行,并显示实际结果行数、实际执行时间和实际内存用量。下面是一个具体的例子:

    1.testdb=# EXPLAIN ANALYZE SELECT id, data FROM tbl_25m ORDER BY id;
    2.                             QUERY PLAN

    3.----------------------------------------------------------------------
    4. Sort  (cost=3944070.01..3945895.01 rows=730000 width=4104) (actual time=885.648..103
    3.746 rows=730000 loops=1)
    5.   Sort Key: id
    6.   Sort Method: external sort  Disk: 10000KB
    7.   ->  Seq Scan on tbl_25m  (cost=0.00..10531.00 rows=730000 width=4104) (actual time
    =0.024..102.548 rows=730000 loops=1)
    8. Planning time: 1.548 ms
    9. Execution time: 1109.571 ms
    10.(6 rows)

在第6行,EXPLAIN命令显示执行器使用了10000KB的临时文件。

临时文件会被临时创建在base/pg_tmp子目录中,并遵循如下命名规则:

{"pgsql_tmp"} + {创建本文件的Postgres进程PID} . {从0开始的序列号}

比如,临时文件pgsql_tmp8903.5是pid为8903的postgres进程创建的第6个临时文件。