Проблемы с производительностью запроса даты в PostgreSQL - PullRequest
2 голосов
/ 12 января 2012

У меня около 5 миллионов строк в таблице postgres. Я хотел бы знать, сколько строк соответствует start_time >= NOW(), но, несмотря на наличие индекса start_time, запрос выполняется крайне медленно (порядка нескольких часов).

EXPLAIN SELECT COUNT(*) FROM core_event WHERE start_time >= NOW();
 Aggregate  (cost=449217.81..449217.82 rows=1 width=0)
   ->  Index Scan using core_event_start_time on core_event  (cost=0.00..447750.83 rows=586791 width=0)
         Index Cond: (start_time >= now())

Вот информация схемы для таблицы:

 id          | integer                  | not null default nextval('core_event_id_seq'::regclass)
 source      | character varying(100)   | not null
 external_id | character varying(100)   | 
 title       | character varying(250)   | not null
 location    | geometry                 | not null
 start_time  | timestamp with time zone | 
 stop_time   | timestamp with time zone | 
 thumb       | character varying(300)   | 
 image       | character varying(100)   | 
 image_thumb | character varying(100)   | 
 address     | character varying(300)   | 
 description | text                     | 
 venue_name  | character varying(100)   | 
 website     | character varying(300)   | 
 city_id     | integer                  | 
 category    | character varying(100)   | 
 phone       | character varying(50)    | 
 place_id    | integer                  | 
 image_url   | character varying(300)   | 
 event_type  | character varying(200)   | 
 hidden      | boolean                  | not null
 views       | integer                  | not null
 added       | timestamp with time zone | 

У меня есть индексы в следующих полях:

city_id
external_id (unique)
location
location_id
place_id
start_time

Есть ли какой-нибудь простой способ ускорить запрос (например, частичный индекс) или мне придется прибегнуть к разбиению данных по дате?

Ответы [ 2 ]

2 голосов
/ 12 января 2012

Попробуйте добавить частичный индекс , как показано ниже:

CREATE INDEX core_event_start_time_recent_idx ON core_event (start_time)
WHERE start_time >= '2011-01-12 0:0'::timestamptz

Это создаст сравнительно небольшой индекс. Создание индекса займет некоторое время, но такие запросы будут намного быстрее после этого.

SELECT count(*) FROM core_event WHERE start_time >= now();

Эффективность этого индекса для запросов против now() будет медленно снижаться с течением времени, в зависимости от того, сколько новых строк поступает. Обновите (= отбросьте и создайте) индекс с более поздней отметкой времени, иногда отключенной ч.
Вы можете автоматизировать это с помощью функции plpgsql, которую вы вызываете за cronjob или pgAgent .


Вы можете попробовать и посмотреть, улучшит ли выполнение CLUSTER на столе (если это не противоречит другим требованиям в вашей БД):

CLUSTER core_event USING core_event_start_time;

Да, кластер на полном индексе, а не на частичном. Это займет некоторое время и потребует эксклюзивной блокировки, поскольку эффективно перезаписывает таблицу. Это также эффективно пылесосит стол полностью. Об этом читайте в руководстве .

Вы также можете увеличить статистическую цель на core_event.start_time;

ALTER core_event ALTER start_time SET STATISTICS 1000; -- example value

По умолчанию просто 100. Тогда:

ANALYZE core_event;

Или, конечно, все обычные рабочие характеристики тоже применимы .

0 голосов
/ 13 января 2012

Большинство этих столбцов заполнены для каждой строки? Если это так, то объем диска, который должен проверить postgresql, чтобы протестировать строки на предмет работоспособности даже после проверки индекса, будет довольно большим. Попробуйте, например, создать отдельную таблицу, которая имеет только id и start_time:

create table core_event_start_time as select id, start_time from core_event;
alter table core_event_start_time add primary key(id);
alter table core_event_start_time add foreign key(id) references core_event(id);
create index on core_event_start_time(start_time);

Теперь посмотрим, сколько времени потребуется для подсчета идентификаторов только в core_event_start_time. Конечно, этот подход потребует больше буферного кеша за счет места для вашей фактической таблицы core_event ...

Если это поможет, вы можете добавить триггер в core_event для обновления вспомогательной таблицы.

(postgresql 9.2 представит «сканирование только по индексу», которое может помочь в такой ситуации, но это на будущее)

...