优化在 pgAdmin 中执行速度比在应用程序中更快的 postgresql 查询以及并发查询

Posted

技术标签:

【中文标题】优化在 pgAdmin 中执行速度比在应用程序中更快的 postgresql 查询以及并发查询【英文标题】:Optimize postgresql query that executes faster in pgAdmin versus in an application along with concurrent queries 【发布时间】:2014-09-01 10:32:31 【问题描述】:

以下 SQL 查询 计算下面列出的架构的每日销售额。在 Sales 表上运行 VACUUM 和 ANALYZE 后,数据没有更新:

 SELECT 
          COUNT("Sales"."ID") AS "Sales->ID"
         ,"Sales"."StoreKeeper" AS "Sales->StoreKeeper"
FROM 
          "Sales" "Sales"
WHERE 
        (
          (
              "Sales"."DayOfSale"  >= 'Sun Aug 03 00:00:00 UTC 2014'
          )
        )
GROUP BY 
          "Sales"."StoreKeeper"
ORDER BY 
          "Sales->ID"
         ,"Sales->StoreKeeper"              

销售表架构和索引:

CREATE TABLE "Sales"
(
  "ID" text NOT NULL,
  "DayOfSale" timestamp without time zone,
  "StoreKeeper" text,
  "CustomerId" text, --ignorable, since no references or joins to any other table
  "Rating" text,
  "Location" text,
  "PaymentType" text, 
  "CashierId" text
 )


 CREATE INDEX saleid_index
   ON "Sales"
   USING btree
  ("ID" COLLATE pg_catalog."default" text_pattern_ops);


  CREATE INDEX sale_dayofsale_index
    ON "Sales"
    USING btree
    ("DayOfSale");
表元数据:6500000 行,所有行都具有相同的“DayOfSale”值 PostgreSQL 版本:64 位 CentOS 上的 9.3.4 硬件:专用机器有 8 GB RAM,只运行 PostGreSQL 服务器 postgresql.conf 中的缓冲区大小: work_mem:500 MB,shared_buffers=2048MB,effective_cache_size=6138MB

2 EXPLAIN 输出:

    当查询在 PgAdmin 中自行执行时的第一个 http://explain.depesz.com/s/m5b http://explain.depesz.com/s/LIIG 作为应用程序的一部分,同时在“Sales”表上触发了大约 7 个查询

观察:

    无论查询是在应用程序中还是在 pgAdmin 中运行,都使用相同的计划。 一种。对于应用程序,所有查询的顺序扫描需要更长的时间 湾。没有。与 PgAdmin 相比,应用程序在 PostGreSQL 缓冲区中的命中率更高

查询:

    顺序扫描花费的时间最多 - 可以使用 调整一些 postgresql.conf 设置? 由于 depesz 强调顺序扫描是最耗时的区域,因此这是最有可能进行调整以帮助提高性能的地方吗?

【问题讨论】:

在解释计划中,我看到了Filter: ("DayOfSale" >= '2014-08-03'::date)。 PostgreSQL 是在执行该转换,还是我们在查看不同的查询? 查询计划显示查询需要 Sales 表中的几乎所有行,因此 seqscan 是一个不错的选择。顺便说一句:你为​​什么使用文本字段作为表格的 PK? @Mike Sherill,PostgreSQL 正在执行演员表。这里只讨论了 1 个查询 @joop,这需要更新架构,但您认为这有助于提高性能吗? ("DayOfSale", "StoreKeeper", "ID")上尝试复合索引 【参考方案1】:

我使用您的 DDL 创建表和索引,然后用 200 万行无意义的数据填充表。

insert into "Sales" ("ID", "DayOfSale", "StoreKeeper", "CustomerId") 
select n, timestamp '2014-08-05 08:00' - (n || ' minutes')::interval, random_integer(1, 100), 3
from generate_series(1, 2000000) n;
analyze "Sales";

我选择“DayOfSale”的值是为了保证只有一小部分表可以满足 WHERE 子句。我希望对此类数据进行索引扫描,而这正是发生的事情。

“排序(成本=173.76..173.76 行=1 宽度=9)(实际时间=2.639..2.647 行=100 循环=1)” " 排序键: (count("ID")), "StoreKeeper"" “排序方法:快速排序内存:29kB” “ -> HashAggregate(成本=173.74..173.75 行=1 宽度=9)(实际时间=2.542..2.557 行=100 循环=1)” “ -> 使用 sale_dayofsale_index 对“销售”进行索引扫描(成本=0.43..156.12 行=3525 宽度=9)(实际时间=0.023..1.184 行=3360 循环=1)” " Index Cond: ("DayOfSale" >= '2014-08-03 00:00:00'::timestamp without time zone)" “总运行时间:2.689 毫秒”

此外,优化器没有从时间戳到日期进行转换。

根据我的经验,如果此表真的是关于销售的,那么很少会报告任意时间范围。我希望对此类数据的查询涉及日历周、日历月或日历年。所以你可能会受益于

部分索引, 表达式的索引,或 分区。

我也想试试covering index。 PostgreSQL 9.2+ 可以进行仅索引扫描;如果您有覆盖索引,则不需要从表中读取数据。

此查询将显示每个月的行数。

select date_trunc('month', "DayOfSale"), count(*)
from "Sales"
group by date_trunc('month', "DayOfSale")
order by 1;

在我的例子中,它显示值的范围是从 2010 年 10 月到 2014 年 8 月。2014 年 8 月只有大约 6000 行,并不是所有这些都满足您的 WHERE 子句。将此查询的结果粘贴到您的问题中可能会很有用。

【讨论】:

感谢 Mike,您的回答促使我仔细检查了您的设置与我的设置之间的差异,因此在我的问题中编辑了数据集大小和元数据。在我的表中,“DayOfSale”只有一个值 - 这就是不使用索引扫描的原因吗? @TreyJonn 如果某个值代表该列值的百分之几以上,则其上的索引没有用。检查cardinality @TreyJonn:是的,索引中的单个值通常会给你一个顺序扫描。不过,您可能仍会从覆盖索引中受益。 (一个索引涵盖查询中的三列:DayOfSale、Storekeeper、ID)【参考方案2】:

我认为你让它变得比它需要的更难。首先,执行 COUNT() 将只考虑一条记录,而不考虑您拥有的 count(Sales.ID) 列。这迫使引擎返回页面数据。如果您只关心给定的 StoreKeeper 有 X 次销售,count() 就可以了。

接下来,索引。我会在 (DayOfSale, StoreKeeper) 上有一个索引,这样,WHERE 子句可以利用索引的 DayofSale 部分,而 StoreKeeper 可以用于优化分组依据。我会完全删除销售 ID 号的订单,因为您关心的只是一般意义上的计数。

简化应该是

select
      s.StoreKeeper,
      count(*) as NumberOfSales
   from
      Sales s
   where
      s.DayOfSale >= 'Sun Aug 03 00:00:00 UTC 2014'

   group by
      s.StoreKeeper
   order by
      s.StoreKeeper

【讨论】:

以上是关于优化在 pgAdmin 中执行速度比在应用程序中更快的 postgresql 查询以及并发查询的主要内容,如果未能解决你的问题,请参考以下文章

SSE 程序在 AMD 上比在 Intel 上花费的时间要长得多

Oracle ODP.NET 托管驱动程序在 64 位中的运行速度比在 32 位中慢 50-100%

为啥这个算法在 python 中的运行速度比在 C++ 中快得多?

为什么这个通过PHP / FastCGI在IIS中运行的java程序比在shell中慢得多?

在 GPU 上训练比在 CPU 上慢得多 - 为啥以及如何加快速度?

优化 PyUno 中的公式复制