这是我的疑问:
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);
然而,正如EXPLAIN
ed,PostgreSQL并不认为如此。它使用此索引中的event
和extra1
,但不使用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)
)
答案 0 :(得分:1)
您需要使用时间戳才能工作,而不是日期。
在纸面上,您可以将索引更改为表达式,以便将日期截断为指定日期。但是如果时间戳有一个时区,这将不起作用,因为它会因为服务器时区改变的理论潜力而变得不稳定。
实际上,您需要将等式子句更改为等效的不等式,例如:类似的东西:
eventDate >= i and eventDate < i + interval '1 day'
但在继续重写查询之前,请注意您只需在Clodoaldo Neto的查询中添加适当的where子句:
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
答案 1 :(得分: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
)
我将日期放在第一位,因为我猜它具有最高cardinality。