上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个临时文件。