performance - Postgres 不在性能中

标签 performance postgresql postgresql-performance

关于如何加快此查询的任何想法?

输入

EXPLAIN SELECT entityid FROM entity e

LEFT JOIN level1entity l1 ON l1.level1id = e.level1_level1id
LEFT JOIN level2entity l2 ON l2.level2id = l1.level2_level2id
WHERE 

l2.userid = 'a987c246-65e5-48f6-9d2d-a7bcb6284c8f' 
AND 
(entityid NOT IN 
(1377776,1377792,1377793,1377794,1377795,1377796... 50000 ids)
)

输出

Nested Loop  (cost=0.00..1452373.79 rows=3865 width=8)
  ->  Nested Loop  (cost=0.00..8.58 rows=1 width=8)
        Join Filter: (l1.level2_level2id = l2.level2id)
        ->  Seq Scan on level2entity l2  (cost=0.00..3.17 rows=1 width=8)
              Filter: ((userid)::text = 'a987c246-65e5-48f6-9d2d-a7bcb6284c8f'::text)
        ->  Seq Scan on level1entity l1  (cost=0.00..4.07 rows=107 width=16)
  ->  Index Scan using fk_fk18edb1cfb2a41235_idx on entity e  (cost=0.00..1452086.09 rows=22329 width=16)
        Index Cond: (level1_level1id = l1.level1id)

这里是一个简化版本,连接不是瓶颈

SELECT enitityid FROM 
(SELECT enitityid FROM enitity e LIMIT 5000) a

WHERE
(enitityid NOT IN 
(1377776,1377792,1377793,1377794,1377795, ... 50000 ids)
)

问题是找到没有这些id的实体

解释

Subquery Scan on a  (cost=0.00..312667.76 rows=1 width=8)
  Filter: (e.entityid <> ALL ('{1377776,1377792,1377793,1377794, ... 50000 ids}'::bigint[]))
  ->  Limit  (cost=0.00..111.51 rows=5000 width=8)
        ->  Seq Scan on entity e  (cost=0.00..29015.26 rows=1301026 width=8)

最佳答案

巨大的 IN 列表效率很低。理想情况下,PostgreSQL 应该识别它并将其转化为它对其进行反连接的关系,但此时查询计划器不知道如何做到这一点,并且识别这种情况所需的计划时间将耗费每个查询明智地使用 NOT IN,因此它必须是一个非常低成本的检查。参见 this earlier much more detailed answer on the topic .

正如 David Aldridge 所写,最好的解决方法是将其变成反连接。我会把它写成 VALUES 列表的连接,因为 PostgreSQL 在将 VALUES 列表解析为关系时速度非常快,但效果是一样的:

SELECT entityid 
FROM entity e
LEFT JOIN level1entity l1 ON l.level1id = e.level1_level1id
LEFT JOIN level2entity l2 ON l2.level2id = l1.level2_level2id
LEFT OUTER JOIN (
    VALUES
    (1377776),(1377792),(1377793),(1377794),(1377795),(1377796)
) ex(ex_entityid) ON (entityid = ex_entityid)
WHERE l2.userid = 'a987c246-65e5-48f6-9d2d-a7bcb6284c8f' 
AND ex_entityid IS NULL; 

对于足够大的一组值,您最好创建一个临时表,COPY将值放入其中,在其上创建一个PRIMARY KEY,然后加入这一点。

更多可能性在这里探索:

https://stackoverflow.com/a/17038097/398670

关于performance - Postgres 不在性能中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17813492/

相关文章:

java - UTC 时间戳 -> java.sql.Timestamp -> jOOQ -> postgreSQL 中的本地时间戳?

c# - Linq2db:查询对象层次结构的有效方法

sql - 在 where 条件中添加 OR 子句比两个单独的查询慢得多

postgresql - Linux 上 PostgreSQL 中的配置参数 work_mem

python numpy 加速 2d 重复搜索

java - Espresso : What are the advantages/disadvantages of having multiple tests vs. 一个用户旅程?

sql - 我如何在 sequelize 中编写这个 Raw Postgres 查询

c++ - 复制一张 map 有多贵?

c# - 在内部使用属性有什么好处?

sql - 在 PostgreSQL 中按字母顺序对字符串中的字母进行排序