如何在PostgreSQL中改写使用IN语句的查询为?

更新于
2026-08-11 08:58:08
2阅读来源:SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

在 PostgreSQL 中。IN 子句是最常用来匹配多值条件的方式之一,但当数据量大、值列表长时它往往成为性能瓶颈。说起来,许多开发者遇到的问题包括:查询执行时间从几秒骤升到数十秒甚至更久;执行计划出现全表扫描或大量临时表;索引无法利用,

使用者痛点一览

  • 执行慢:包含几十甚至上百个常量的 IN 列表导致 PostgreSQL 采用 Seq Scan 或 Bitmap Heap Scan。
  • 计划不稳定:不同会话或不同参数下执行计划可能切换,导致性能不可预期。
  • 维护困难:IN 列表如果是动态生成的,在代码中难以管理、难以重用。
  • 可读性差:长列表在 SQL 文本里显得杂乱,难以维护。

常见调整思路

1️⃣ VALUES 子句 + JOIN

将 IN 列表 为 VALUES 子句,接下来用 JOIN 与主表连接。这样可以让 PostgreSQL 在执行计划中使用 Index Scan 或 Hash Join,从而显著提高性能。

如何在PostgreSQL中
使用IN语句的查询为?
-- 原始写法
SELECT * FROM users WHERE id IN;--
后
SELECT u.*
FROM users u
JOIN,,,) AS v ON u.id = v.id;

优点

  • 避免了 IN 的内部实现开销。说起来,
  • 可以直接利用主键或唯一索引。
  • 支持动态生成值列表。

2️⃣ EXISTS 子查询

If IN 列表来自另一个表。可以用 EXISTS 替代,它往往能让调整器选择更高效的方法。

-- 原始写法
SELECT *
FROM orders o
WHERE o.customer_id IN (
SELECT id FROM customers WHERE status = 'active'
);说起来,--
后
SELECT *
FROM orders o
WHERE EXISTS (
SELECT 1 FROM customers c
WHERE c.id = o.customer_id AND c.status = 'active'
);

何时使用?

  • I/O 密集型子查询。说起来,
  • Avoids duplicate rows caused by a non‑unique subquery.
  • Simplifies NULL handling.

3️⃣ ANY / ALL 操作符

PgSQL 支持将数组与 ANY / ALL 操作符配合使用。语义与 IN 等价,但对调整器友好度更高。

SELECT *
FROM products p
WHERE p.category_id = ANY;

注意:If array is large。仍建议使用 VALUES+JOIN,因为数组会占用更多内存并可能导致临时文件产生。

4️⃣ 使用 ARRAY 并开启 parallelism

PgSQL 在较新版本中支持 Parallel Array Contains 查询,可利用多核并行提高速度。但前提是硬件资源充足,还有查询已被充分调整。示例的观点是,

SET max_parallel_workers_per_gar = 4;SELECT *
FROM big_table t
WHERE t.key = ANY;

再看实战案例,从慢到快的完整 过程

  1. # 原始慢查询:SELECT * FROM orders WHERE customer_id IN; 因为列表长度超百且缺乏索引扫描策略导致 Seq Scan。

如何在PostgreSQL中
使用IN语句的查询为?

  • # 步骤一:检查索引是否覆盖字段:CREATE INDEX IF NOT EXISTS idx_orders_customer_id ON orders;
  • # 步骤二: 为 VALUES + JOIN:SELECT o.* FROM orders o JOIN。...,) AS v ON o.customer_id=v.id;
  • # 步骤三:验证执行计划:EXPLAIN ANALYZE显示 Hash Join 或 Index Scan,用时仅 ~0.8 秒。其实,
  • # 步骤四:监控 & 调优进一步细节:
    • - 检查是否存在多余列导致宽行影响 I/O;
    • - 考虑将 VALUES 表变成临时表,用 CREATE TEMP TABLE 并加索引;
  • # 完成!性能提高约40 倍,且可读性明显提高。
    • ✔ 可维护性提高;
    • ✔ 执行计划稳定;
    • ✔ 对大型数据集友好。

    小贴士:  "在实际项目中。如果值列表来源于业务逻辑,可以考虑把它们存放在临时表或缓存层,而不是硬编码在 SQL 字面量里。"

    © PostgreSQL 社区文档整理     

    标签:数据库中

    在 PostgreSQL 中。IN 子句是最常用来匹配多值条件的方式之一,但当数据量大、值列表长时它往往成为性能瓶颈。说起来,许多开发者遇到的问题包括:查询执行时间从几秒骤升到数十秒甚至更久;执行计划出现全表扫描或大量临时表;索引无法利用,

    使用者痛点一览

    • 执行慢:包含几十甚至上百个常量的 IN 列表导致 PostgreSQL 采用 Seq Scan 或 Bitmap Heap Scan。
    • 计划不稳定:不同会话或不同参数下执行计划可能切换,导致性能不可预期。
    • 维护困难:IN 列表如果是动态生成的,在代码中难以管理、难以重用。
    • 可读性差:长列表在 SQL 文本里显得杂乱,难以维护。

    常见调整思路

    1️⃣ VALUES 子句 + JOIN

    将 IN 列表 为 VALUES 子句,接下来用 JOIN 与主表连接。这样可以让 PostgreSQL 在执行计划中使用 Index Scan 或 Hash Join,从而显著提高性能。

    如何在PostgreSQL中
使用IN语句的查询为?
    -- 原始写法
    SELECT * FROM users WHERE id IN;--
    后
    SELECT u.*
    FROM users u
    JOIN,,,) AS v ON u.id = v.id;

    优点

    • 避免了 IN 的内部实现开销。说起来,
    • 可以直接利用主键或唯一索引。
    • 支持动态生成值列表。

    2️⃣ EXISTS 子查询

    If IN 列表来自另一个表。可以用 EXISTS 替代,它往往能让调整器选择更高效的方法。

    -- 原始写法
    SELECT *
    FROM orders o
    WHERE o.customer_id IN (
    SELECT id FROM customers WHERE status = 'active'
    );说起来,--
    后
    SELECT *
    FROM orders o
    WHERE EXISTS (
    SELECT 1 FROM customers c
    WHERE c.id = o.customer_id AND c.status = 'active'
    );

    何时使用?

    • I/O 密集型子查询。说起来,
    • Avoids duplicate rows caused by a non‑unique subquery.
    • Simplifies NULL handling.

    3️⃣ ANY / ALL 操作符

    PgSQL 支持将数组与 ANY / ALL 操作符配合使用。语义与 IN 等价,但对调整器友好度更高。

    SELECT *
    FROM products p
    WHERE p.category_id = ANY;
    

    注意:If array is large。仍建议使用 VALUES+JOIN,因为数组会占用更多内存并可能导致临时文件产生。

    4️⃣ 使用 ARRAY 并开启 parallelism

    PgSQL 在较新版本中支持 Parallel Array Contains 查询,可利用多核并行提高速度。但前提是硬件资源充足,还有查询已被充分调整。示例的观点是,

    SET max_parallel_workers_per_gar = 4;SELECT *
    FROM big_table t
    WHERE t.key = ANY;

    再看实战案例,从慢到快的完整 过程

    1. # 原始慢查询:SELECT * FROM orders WHERE customer_id IN; 因为列表长度超百且缺乏索引扫描策略导致 Seq Scan。

    如何在PostgreSQL中
使用IN语句的查询为?

  • # 步骤一:检查索引是否覆盖字段:CREATE INDEX IF NOT EXISTS idx_orders_customer_id ON orders;
  • # 步骤二: 为 VALUES + JOIN:SELECT o.* FROM orders o JOIN。...,) AS v ON o.customer_id=v.id;
  • # 步骤三:验证执行计划:EXPLAIN ANALYZE显示 Hash Join 或 Index Scan,用时仅 ~0.8 秒。其实,
  • # 步骤四:监控 & 调优进一步细节:
    • - 检查是否存在多余列导致宽行影响 I/O;
    • - 考虑将 VALUES 表变成临时表,用 CREATE TEMP TABLE 并加索引;
  • # 完成!性能提高约40 倍,且可读性明显提高。
    • ✔ 可维护性提高;
    • ✔ 执行计划稳定;
    • ✔ 对大型数据集友好。

    小贴士:  "在实际项目中。如果值列表来源于业务逻辑,可以考虑把它们存放在临时表或缓存层,而不是硬编码在 SQL 字面量里。"

    © PostgreSQL 社区文档整理     

    标签:数据库中