5

在 PostgreSql 8.4 查询中

explain analyze SELECT 
    max( kuupaev||kellaaeg ) as res
  from ALGSA 
  where laonr=1 and kuupaev <='9999-12-31' and 
     kuupaev||kellaaeg <= '9999-12-3123 59'

运行需要 3 秒:

"Aggregate  (cost=3164.49..3164.50 rows=1 width=10) (actual time=2714.269..2714.270 rows=1 loops=1)"
"  ->  Seq Scan on algsa  (cost=0.00..3110.04 rows=21778 width=10) (actual time=0.105..1418.743 rows=70708 loops=1)"
"        Filter: ((kuupaev <= '9999-12-31'::date) AND (laonr = 1::numeric) AND ((kuupaev || (kellaaeg)::text) <= '9999-12-3123 59'::text))"
"Total runtime: 2714.363 ms"

如何在 PostgreSQL 8.4.4 中加快速度?表结构如下。algsa 表在 kuupaev 上有索引也许可以使用?或者是否可以更改查询以添加一些其他索引以使其快速。表中的现有列无法更改。

CREATE TABLE firma1.algsa
(
  id serial NOT NULL,
  laonr numeric(2,0),
  kuupaev date NOT NULL,
  kellaaeg character(5) NOT NULL DEFAULT ''::bpchar,
  ... other columns
  CONSTRAINT algsa_pkey PRIMARY KEY (id),
  CONSTRAINT algsa_id_check CHECK (id > 0)
)
);

CREATE INDEX algsa_kuupaev_idx  ON firma1.algsa  USING btree  (kuupaev);

更新

试过了analyze verbose firma1.algsa;

INFO:  analyzing "firma1.algsa"
INFO:  "algsa": scanned 1640 of 1640 pages, containing 70708 live rows and 13 dead rows; 30000 rows in sample, 70708 estimated total rows
Query returned successfully with no result in 1185 ms.

但查询运行时间仍然是 2.7 秒。

为什么有30000 rows in sample 。是不是太多了,应该减少吗?

4

2 回答 2

6

这是旧版本 PostgreSQL 中的一个已知问题 - 但看起来它可能已被 8.4 解决;事实上,8.0 的文档有警告,但8.1 的文档没有。

因此,至少,您不需要出于这个原因升级主要版本。但是,您应该升级到当前的 8.4 系列版本 8.4.16,因为您错过了数的错误修复和调整。

这里真正的问题是您使用max的是表达式,而不是简单的值,并且该表达式没有函数索引。

您可以尝试在表达式上创建索引kuupaev||kellaaeg......但我怀疑您有数据模型问题,并且通过修复您的数据模型有更好的解决方案。

它看起来像是kuupaevkuupäev 或日期,而 kellaaeg 可能是时间。如果是这样:永远不要使用连接 ( ||) 运算符来组合日期和时间;使用区间加法,例如kuupaev + kellaaeg。而不是char您应该使用数据类型或time约束for ,这取决于它的含义以及它是否限制为 24 小时。或者,更好的是,使用类型(本地时间)或(全球时间)的单个字段来存储组合的日期和时间。intervalCHECKkellaaegtimestamptimestamp with time zone

如果您这样做,您可以在组合列上创建一个简单的索引来替换两者kellaaegkuupaev并将其用于minmax其他用途。如果您只需要日期部分或某些事情的时间部分,请使用date_trunc,extractdate_part函数;请参阅文档。

有关单独和列是一个坏主意的另一个示例,请参见这个较早的答案。datetime

您仍然应该计划升级到 9.2。从 8.4 到 9.2 的升级路径并不算太粗糙,你只需要注意standard_conforming_strings默认的 on 设置和bytea_outputfromescape到的变化hex。在过渡和移植工作期间,两者都可以设置回 8.4 默认值。8.4 将不再受支持。

于 2013-02-19T10:21:20.737 回答
3

我的第一反应是尝试索引:

 create index algsa_laonr_kuupaev_kellaaeg_idx
 on ALGSA (laonr asc, (kuupaev||kellaaeg) desc)

...并尝试查询:

 SELECT kuupaev||kellaaeg as res
 from ALGSA 
 where laonr=1 and
       kuupaev||kellaaeg <= '9999-12-3123 59'
 order by
       laonr asc,
       kuupaev||kellaaeg desc
 limit 1
于 2013-02-19T10:26:44.807 回答