似乎NOT IN降低了Postgresql查询的性能

时间:2020-02-02 11:05:40

标签: sql postgresql

我在这里附加了一个查询,用于分析结果,https://explain.depesz.com/s/x9BN

这是查询

EXPLAIN ANALYZE 
     SELECT 
          branches.id as branch_id, 
          date(products.created_at + interval '1 hours 0 minutes') as date, 
          SUM(total_amount) as totalamount 
     FROM "products" 
     INNER JOIN "branches" ON "branches"."id" = "products"."branch_id" 
     WHERE (products.order_status_id NOT IN (10, 5, 50)) 
     AND (products.company_id = 190) 
     AND (
          products.created_at 
          BETWEEN '2019-01-30 23:00:00.000000' 
          AND '2019-12-30 23:00:00.000000'
     ) 
     GROUP BY branches.id, date;

我可以看到更多时间花在NOT IN()的使用上。

我们还有其他功能可以用来提高性能。

2 个答案:

答案 0 :(得分:3)

您的时间花费在访问许多包含您要搜索的行的表块上。也许许多块没有被缓存,并且存储也不快。

此查询可能永远不会比以前快,但您可以尝试以下两种方法:

  1. 使用多列索引:

    #attributen button[class=color-changer], 
      #attributen input[id="reset"] {    
        width: 140px;    
        height: 35px;
     }
    
  2. 如果这还不够快,请重写表,以使块按索引顺序物理排列:

    CREATE INDEX ON products (company_id, creazed_at);
    

    然后,将所需的行集中在较少的表块中,因此读取它们应该更快。

    请注意,CLUSTER products USING idx_products_company_and_branch; 会阻止表在运行时对表的所有访问,并且由于表的修改会降低顺序,因此必须不时地对其进行重复。

答案 1 :(得分:2)

我怀疑not in与常量是否直接导致您的性能问题。如果您发现问题,那是因为NOT IN正在更改查询计划。

对于您而言,您拥有一些Postgres试图使用的部分有用的索引。我怀疑它提出了错误的查询计划,因为统计信息已过时。

对于此查询:

SELECT b.id as branch_id, 
       date(p.created_at + interval '1 hours 0 minutes') as date, 
       SUM(total_amount) as totalamount 
 FROM "products" p JOIN
      "branches" b
      ON b."id" = p."branch_id" 
 WHERE p.order_status_id NOT IN (10, 5, 50) AND 
       p.company_id = 190 AND 
       p.created_at >= '2019-01-30 23:00:00.000000' AND
       p.created_at < '2019-12-30 23:00:00.000000'
 GROUP BY b.id, date;

请注意,我调整了日期比较,因为between包括两个端点。

我建议以下索引:

  • products(company_id, created_at, order_status_id)
  • branches(id)