Е, и двете ви заявки са на различни таблици (reportimpression
спрямо reportimpressionday
), така че сравнението на двете заявки наистина не е сравнение. АНАЛИЗИРАХТЕ
ли? и двете? Различни статистически данни за колони също могат да играят роля. Раздуването на индекса или таблицата може да е различно. По-голяма част от всички редове отговарят ли на изискванията за февруари 2019 г.? И т.н.
Един изстрел в тъмното, сравнете процентите за двете таблици:
SELECT tbl, round(share * 100 / total, 2) As percentage
FROM (
SELECT text 'reportimpression' AS tbl
, count(*)::numeric AS total
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')::numeric AS share
FROM reportimpression
UNION ALL
SELECT 'reportimpressionday'
, count(*)
, count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')
FROM reportimpressionday
) sub;
Това е за reportimpression
по-голям? Тогава може просто да надхвърли броя, за който се очаква индексът да помогне.
Обикновено вашият индекс reportimpression_datelocal_index
на (местна дата) изглежда добре за него и reportimpression_viewership_index
дори позволява сканиране само за индекс, ако autovacuum победи натоварването на запис върху масата. (Въпреки че импресии
&възрастова група
са просто мъртъв товар за това и ще работи дори по-добре без).
Отговор
Имате 26,6 процента, а денят е 26,4 процента
за моето запитване. За такъв голям процент индексите обикновено изобщо не са полезни . Последователното сканиране обикновено е най-бързият начин. Само сканиране само с индекс може все пак има смисъл, ако основната таблица е много по-голяма. (Или имате тежка раздуване на таблицата и по-малко раздути индекси, което прави индексите отново по-привлекателни.)
Първото ви запитване може просто да е през повратната точка. Опитайте да стесните времевата рамка, докато видите сканирания само за индекс. Няма да видите (растерно) сканиране на индекс с повече от приблизително 5% от всички редове, отговарящи на условията (зависи от много фактори).
Заявки
Както и да е, разгледайте тези модифицирани заявки:
SELECT date_part('hour', datelocal) AS hour
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpression
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01' -- '2019-02-28' -- ?
GROUP BY 1
ORDER BY 1;
SELECT date_trunc('day', datelocal) AS day
, SUM(views) FILTER (WHERE gender = 'male') AS male
, SUM(views) FILTER (WHERE gender = 'female') AS female
FROM reportimpressionday
WHERE datelocal >= '2019-02-01'
AND datelocal < '2019-03-01'
GROUP BY 1
ORDER BY 1;
Основни точки
-
Когато използвате локализиран формат за дата като
'2-1-2019'
, преминете презto_timestamp()код>
с изрични спецификатори на формат. В противен случай това зависи от локалните настройки и може да прекъсне (тихо) при извикване от сесия с различни настройки. По-скоро използвайте ISO формати за дата/час, както е показано, които не зависят от локалните настройки. -
Изглежда, че искате да включите целия месец от февруари. Но вашата заявка пропуска горната граница. От една страна, февруари може да има 29 дни.
локална дата <'2-28-2019'
изключва и всички 28 фев. Използвайтеdatelocal <'2019-03-01'
вместо това. -
По-евтино е да групирате и сортирате по един и същи израз както имате в
SELECT
изброй, ако можеш. Затова използвайтеdate_trunc()
там също. Не използвайте различни изрази без нужда. Ако имате нужда частта от датата в резултата, приложете я върху групирания израз, като:SELECT date_part('day', date_trunc('day', datelocal)) AS day ... GROUP BY date_trunc('day', datelocal) ORDER BY date_trunc('day', datelocal);
Малко по-шумен код, но по-бърз (и вероятно по-лесен за оптимизиране и за планиране на заявки).
-
Използвайте обединения
ФИЛТЪР
клаузата в Postgres 9.4 или по-нова версия. По-чист е и малко по-бърз. Вижте: