4

这是我的查询:

SELECT
    i::date AS day,
    (SELECT COUNT(*) FROM genericevent WHERE event = 'chat_message' AND eventDate::date = i::date AND extra1 = 'public') AS message_public_total,
    (SELECT COUNT(*) FROM genericevent WHERE event = 'chat_message' AND eventDate::date = i::date AND extra1 = 'public' AND extra2 = 'clean') AS message_public_clean
FROM generate_series('2013-08-01', '2013-08-27', INTERVAL '1 day') i

我有一个索引,作为人类,我认为它完全可用于此查询(实际上它应该导致仅索引扫描):

CREATE INDEX idx__genericevent__event__extra1__date
  ON genericevent
  USING btree
  (event COLLATE pg_catalog."default", extra1 COLLATE pg_catalog."default", eventDate);

然而,正如EXPLAINed 所说,PostgreSQL 并不这么认为。它使用eventextra1来自这个索引,但不是eventDate(见Index Cond行):

"Function Scan on generate_series i  (cost=0.00..145219698.17 rows=1000 width=8)"
"  SubPlan 1"
"    ->  Aggregate  (cost=72274.87..72274.88 rows=1 width=0)"
"          ->  Bitmap Heap Scan on genericevent  (cost=11367.74..72271.51 rows=1345 width=0)"
"                Recheck Cond: (((event)::text = 'chat_message'::text) AND ((extra1)::text = 'public'::text))"
"                Filter: ((eventDate)::date = (i.i)::date)"
"                ->  Bitmap Index Scan on idx__genericevent__event__extra1__date  (cost=0.00..11367.40 rows=269012 width=0)"
"                      Index Cond: (((event)::text = 'chat_message'::text) AND ((extra1)::text = 'public'::text))"
"  SubPlan 2"
"    ->  Aggregate  (cost=72944.79..72944.80 rows=1 width=0)"
"          ->  Bitmap Heap Scan on genericevent  (cost=11367.50..72943.80 rows=396 width=0)"
"                Recheck Cond: (((event)::text = 'chat_message'::text) AND ((extra1)::text = 'public'::text))"
"                Filter: (((extra2)::text = 'clean'::text) AND ((eventDate)::date = (i.i)::date))"
"                ->  Bitmap Index Scan on idx__genericevent__event__extra1__date  (cost=0.00..11367.40 rows=269012 width=0)"
"                      Index Cond: (((event)::text = 'chat_message'::text) AND ((extra1)::text = 'public'::text))"

eventDate::date我认为这可能需要演员做点什么。如何更改查询或索引以提高性能?

为了完整起见,下表是:

CREATE TABLE genericevent
(
  id bigint NOT NULL,
  eventDate timestamp with time zone NOT NULL,
  event character varying(50) NOT NULL,
  extra1 character varying(100),
  extra2 character varying(100),
  CONSTRAINT genericevent_pkey PRIMARY KEY (id)
)
4

2 回答 2

1

您需要使用时间戳才能使其工作,而不是日期。

在纸面上,您可以将索引更改为表达式,以便将日期截断为指定日期。但是,如果时间戳有一个时区,这将不起作用,因为由于服务器的时区理论上可能发生变化,所以它是不稳定的。

在实践中,您需要将相等子句更改为等效的不等式,例如:

eventDate >= i and eventDate < i + interval '1 day'

但在继续重写查询之前,请注意您可以简单地将适当的 where 子句添加到 Clodoaldo Neto 的查询中:

select
    i::date as day,
    count(*) as message_public_total,
    count(extra2 = 'clean' or null) as message_public_clean
from
    genericevent
    right join
    generate_series(
        '2013-08-01', '2013-08-27', interval '1 day'
    ) i on eventdate::date = i::date
where
    event = 'chat_message'
    and extra1 = 'public'
    and eventDate >= '2013-08-01'
    and eventDate < '2013-08-27' + interval '1 day'
group by 1

或者:

select
    i::date as day,
    count(*) as message_public_total,
    count(extra2 = 'clean' or null) as message_public_clean
from
    genericevent
    right join
    generate_series(
        '2013-08-01', '2013-08-27', interval '1 day'
    ) i on eventdate >= i and eventDate < i + interval '1 day'
where
    event = 'chat_message'
    and extra1 = 'public'
--    and eventDate >= '2013-08-01'
--    and eventDate < '2013-08-27' + interval '1 day'
group by 1
于 2013-08-28T10:16:37.927 回答
0

这个等效的查询只扫描一个,而不是你的两个。

select
    i::date as day,
    count(*) as message_public_total,
    count(extra2 = 'clean' or null) as message_public_clean
from
    genericevent
    right join
    generate_series(
        '2013-08-01', '2013-08-27', interval '1 day'
    ) i on eventdate::date = i::date
where
    event = 'chat_message'
    and extra1 = 'public'
group by 1

那么索引将是

create index idx on genericevent (
    eventDate::date,
    event,
    extra1   
)

我把日期放在第一位,因为我猜它的基数最高。

于 2013-08-28T09:43:43.853 回答