MySQL和PostgreSQL之间的差异通常微不足道,但偶尔也会有明显的差异。希望在PostgreSQL服务器上优化查询的MySQL DBA将有一些使用EXPLAIN的经验。对于未初始化的用户,关键字EXPLAIN将预先挂起到查询中,以显示服务器想要执行哪些操作来返回该查询中请求的数据。解释的两个版本的实现非常不同。PostgreSQL for MySQL DBA系列的第六集包括解释。
那么有什么不同呢? PostgreSQL添加了XML和YAML输出格式选项,超越了MySQL中的传统和JSON。至少在我看来,PostgreSQL的输出看起来像MySQL的树输出。但由于这两个数据库“机械”不同,您需要学习如何解释PostgreSQL提供的输出。
下面的示例提供了详细信息,例如服务器获取数据的机制、启动成本、总体成本、要返回的行数以及使用的键的名称(如果有)。有关详细信息,请参阅视频。
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)
复制
请参阅视频以了解差异,并快速介绍PostgreSQL的解释。
测验答案
我在演示文稿和视频中添加了一个“奖励问答题”。
视频中的奖励问答题
第一个做出回应的人是杰克·T:
您之前说过,“序列扫描”是全表扫描,仅执行该扫描需要15.54毫秒。理论上,如果在postal_ code上添加索引,则这将变为“索引扫描”,执行时间将减少。在MySQL中,该子查询模式被识别为“半连接”,并作为连接执行。PGSQL是否有类似的重写优化?
这就是使用一个数据库的经验可以帮助您掌握另一个数据库。通常,添加索引将加快查询速度。但要了解PostgreSQL,需要记住的一件大事是,它有不同的处理方式。
让我们重新运行EXPLAIN,谢天谢地,这些数字与我的测试机匹配。
dvdrental=# 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) <span style="font-size: 10px;">(5 rows)</span>
复制
然后我们可以在postal_code列中创建索引。
dvdrental=# CREATE INDEX quiz_answer_1 ON address (postal_code); CREATE INDEX
复制
因此,我们重新运行EXPLAIN并查看结果。
dvdrental=# 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) (7 rows)
复制
结果很有趣。请注意,idx_fx_address_id的索引扫描成本保持不变,因为新索引在客户表上不起作用,但新索引确实将地址扫描从15.54降到了9.32。嵌套外观成本从32.14降到了25.92。优化是位图扫描。
根据PostgreSQL手册,规划人员决定使用两步计划:底部计划节点访问索引以查找与索引条件匹配的行的位置,然后上部计划节点实际从表本身获取这些行。单独获取行比顺序读取行要昂贵得多,但由于不必访问表中的所有页面,因此这仍然比顺序扫描便宜。(使用两级计划的原因是,上层计划节点在读取索引之前将索引标识的行位置按物理顺序排序,以最小化单独提取的成本。节点名称中提到的“位图”是进行排序的机制。)
因此,索引确实加快了查询速度,但优化的方式与MySQL使用的方式大不相同。
下一集—真空清理表
敬请期待!
PostgreSQL for MySQL数据库管理员(DBA)过去的视频可以在这里找到:第一集、第二集、第三集、第四集和第五集。
作者
David Stokes是Percona公司的技术传道者,是MySQL和JSON的作者-实用编程指南,居住在德克萨斯州。
原文标题:PostgreSQL for MySQL DBAs Episode 6 – Explaining EXPLAIN (And an Answer to a Bonus Question)
原文作者:David Stokes
原文链接:https://www.percona.com/blog/postgresql-for-mysql-dbas-episode-6-explaining-explain-and-an-answer-to-a-bonus-question/