除了传统和JSON之外,PostgreSQL中添加了XML和YAML格式选项。至少在我看来,PostgreSQL输出看起来像MySQL的TREE输出。
以下示例提供了详细信息,例如服务器将用于获取数据的机制、启动成本、总成本、要返回的行数以及使用的键的名称(如果有)。
test=# EXPLAIN SELECT 1 FROM t1 WHERE ID=101; QUERY PLAN ----------------------------------------------------------------------- Index Only Scan using t1_pkey on t1 (cost=0.29..4.31 rows=1 width=4) Index Cond: (id = 101) (2 rows)
你说"Seq Scan"是全表扫描,执行该扫描需要15.54毫秒。理论上,如果你在postal_code上添加一个索引,那么它会变成一个"Index Scan"并且执行时间应该会减少。
在MySQL中,此子查询模式被识别为"semi-join"并作为JOIN执行。PGSQL是否有类似的重写优化?
这就是使用一个数据库的经验可以帮助你掌握另一个数据库的地方。通常添加索引会加快查询速度。但是要记住的关于PostgreSQL的重要知识之一是它有不同的做事方式。
让我们重新运行EXPLAIN:
=# EXPLAIN SELECT * FROM customer WHERE address_id IN (SELECT address_id FROM address WHERE postal_code = '52137'); QUERY PLAN ----------------------------------------------------------------------------------------- Nested Loop (cost=0.28..32.14 rows=2 width=70) -> Seq Scan on address (cost=0.00..15.54 rows=2 width=4) Filter: ((postal_code)::text = '52137'::text) -> Index Scan using idx_fk_address_id on customer (cost=0.28..8.29 rows=1 width=70) Index Cond: (address_id = address.address_id) (5 rows)
然后,可以再postal_code列上创建索引。
=# CREATE INDEX quiz_answer_1 ON address (postal_code); CREATE INDEX
再次执行explain:
=# EXPLAIN SELECT * FROM customer WHERE address_id IN (SELECT address_id FROM address WHERE postal_code = '52137'); QUERY PLAN ----------------------------------------------------------------------------------------- Nested Loop (cost=4.57..25.92 rows=2 width=70) -> Bitmap Heap Scan on address (cost=4.29..9.32 rows=2 width=4) Recheck Cond: ((postal_code)::text = '52137'::text) -> Bitmap Index Scan on quiz_answer_1 (cost=0.00..4.29 rows=2 width=0) Index Cond: ((postal_code)::text = '52137'::text) -> Index Scan using idx_fk_address_id on customer (cost=0.28..8.29 rows=1 width=70) Index Cond: (address_id = address.address_id)
结果很有趣。请注意,对idx_fk_address_id进行索引扫描的成本保持不变,因为新索引在customer表上不起作用。
但新索引确实将地址的扫描从15.54降低到9.32。Nested Loop成本从32.14下降到25.92。优化是使用位图扫描。
从PostgreSQL手册–这里计划器决定使用两步计划:bottom计划节点访问索引以查找与索引条件匹配的行的位置,然后upper计划节点实际上从表本身中获取这些行。单独获取行比顺序读取要昂贵得多,但由于不必访问表的所有页,这仍然比顺序扫描成本低。
(之所以使用两级计划,是因为上层计划节点在读取之前将索引标识的行位置排序为物理顺序,以尽量减少单独提取的成本。节点名称中提到的"位图"是进行排序的机制。)
因此,索引确实加快了查询速度,但与MySQL使用的优化有很大不同。