在 PostgreSQL 中优化含 ‘IN’ 子查询的 SQL 语句有哪些方法 ?

以下是我近期博客中的一条 SQL 语句。有读者询问在子查询的选择列表添加 +0(例如 b.emp_grade+0)对性能的影响。我很欣喜地得知,这个 +0 解决方案大约在 20 年前首次由我提出,用于解决特定子查询问题。不过该方法现已被 COALESCE(b.emp_grade, b.emp_grade) 替代——此举既能规避数据类型检测,又可预防意外错误。

今天,我想进一步探讨利用 IN 子查询优化 SQL 的其他解决方案。

select *
  from grade
 where grd_id in (select b.emp_grade
                    from employee b
                   where b.emp_id > 3000000)

以下截图展示了由 Tosska SQL Tuning Expert Pro 通过’仅重写’选项和 ‘SQL调优智能=2’ 生成的替代SQL方案。我将分享更多SQL重写方法,全面展示各种可能方案,期待以SQL调优技术的精妙艺术激发读者的探索热情。

以下虽不深入探讨具体SQL重写语句细节,但我很乐意分享其余查询重写方案及其对应的执行计划:

Tosska SQL Tuning Expert Pro for PostgreSQL – Tosska Technologies Limited

如何为 openGauss 调优带有“IN 子查询”的 SQL ?

openGauss 是一种开源的关系型数据库管理系统(RDBMS),它起源于 PostgreSQL。openGauss 旨在提供高性能、高可用性和企业级功能。最初由华为开发,后来被开源给社区。openGauss 的 SQL 优化器基于 PostgreSQL,但经过了显著的增强和修改,以提升性能、可扩展性并支持企业级工作负载。虽然官方文档中没有明确说明 openGauss 是从哪个 PostgreSQL 版本继承的初始代码库,但普遍认为 openGauss 起源于 PostgreSQL 9.2.4。因此,当前版本的 openGauss 中可能仍然存在一些来自旧版 PostgreSQL 的遗留 SQL 优化器问题。

在不成熟的 SQL 优化器中,一个常见问题是对 IN 子查询的低效处理。以下是一个带有 IN 子查询的 SQL 语句示例。该查询从 employee 表中检索与 emp_subsidiary 表中 salary 匹配的记录,条件是两者的 emp_id 相同。

select *
  from employee a
 where a.emp_salary in (select b.emp_salary
                          from emp_subsidiary b
                         where a.emp_id = b.emp_id)

以下是查询计划;完成该查询需要 7.2 秒。

查询计划显示了对 employee 表的顺序扫描(sequence scan)和对 emp_subsidiary 表的索引扫描(index scan)。然而,这种查询不适合 employee 与 emp_subsidiary 比例为 30:1 的场景。如果 openGauss 拥有更强大的 SQL 优化器,它应该包含一个内部的 SQL 语法重写机制,将 IN 语句转换为 JOIN 或 EXISTS 语句,从而允许探索更高效的查询计划。>br>

下面,我将使用 EXISTS 语句重写 SQL,如下所示:

select *
  from employee a
 where exists (select ‘x’
                 from emp_subsidiary b
                where a.emp_salary = b.emp_salary and
                      a.emp_id = b.emp_id)


重写后的 SQL 仅需 0.34 秒 即可完成,并且在查询计划中使用了 Merge Semi Join——这是一种无法通过原始 IN 语法生成的计划。我们可以看到,重写后的 SQL 成本显著低于原始 SQL 语句。这表明,在 openGauss 对原始查询进行 SQL 优化时,Merge Semi Join 计划并未在其探索的计划空间内。

重写后的 SQL 比原始 SQL 快 20 倍以上。这种优化也可以通过使用 Tosska SQL Tuning Expert 在 openGauss 中实现。

Tosska SQL Tuning Expert Pro (TSEG Pro™) for openGauss® – 珠海图思科软件有限公司