【问题标题】:postgres query with IN is very slow使用 IN 的 postgres 查询非常慢
【发布时间】:2017-01-07 21:00:12
【问题描述】:

我有一个在(A 列,B 列)上有索引的表。我正在运行一个如下所示的查询:

SELECT * FROM table WHERE (A, B) IN ((a_1, b_1), (a_2, b_2), ..., (a_5000, b_5000))

这个查询很慢! 计划如下:

Bitmap Heap Scan on table
  Recheck Cond: (((A = a_1) AND (B = b_1)) OR ((A = a_2) AND (B = b_2)) OR ...
  ->  BitmapOr
        ->  Bitmap Index Scan on idx
              Index Cond: ((A = a_1) AND (B = b_1))
        ->  Bitmap Index Scan on idx
              Index Cond: ((A = a_2) AND (B = b_2))
        ...(5000 other Bitmax Index Scan)

postgres 似乎一次只对一个值进行 5000 次索引扫描,而不是对 5000 个值进行一次索引扫描,这解释了为什么查询如此缓慢。

实际上,这样做会更快:

SELECT * FROM table WHERE A IN (a_1, ..., a_5000)

获取结果,然后在应用程序 (python) 内的 B 列上进行过滤。

我真的希望结果已经被 postgres 过滤并具有合理的运行时间。有解决办法吗?

【问题讨论】:

    标签: sql postgresql postgresql-performance


    【解决方案1】:

    尝试加入 CTE:

    with value_list (a,b) as (
      values 
          (a_1, b_1), 
          (a_2, b_2), ..., 
          (a_5000, b_5000) 
    )
    select *
    from table t
      join value_list v on (t.a, t.b) = (v.a, v.b);
    

    (假设您在值列表中没有重复项)

    【讨论】:

    • 这很有趣。为什么会有任何不同?
    • @zerkms:理论(希望)是它会欺骗优化器对所有值进行一次索引扫描,而不是对每个值进行一次扫描。
    • 有效!规划器确实只使用了一个哈希连接。虽然规划器不够聪明,无法处理第一个查询,但我觉得很奇怪。
    • @MehdiGMIRA:对于单列 IN 列表,优化器工作正常。只是这种情况并没有以最好的方式处理——但 Postgres 并不孤单。 Oracle 根本不会考虑为(a,b) in (...) 创建索引,即使条件只返回表的一小部分。在我的笔记本电脑上有一个有 700.000 行的表,Postgres 上的 IN 查询只需 1.5 秒即可返回 1000 行。 Oracle 需要 50 秒。所以即使计划不完美,其实也没有那么糟糕。
    • @a_horse_with_no_name 这令人印象深刻!
    猜你喜欢
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2022-10-13
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    相关资源
    最近更新 更多