Postgres не выполняется сканирование только индекса - PullRequest
0 голосов
/ 12 июля 2020

У меня есть такой запрос

explain analyze
SELECT user_id, project_id, office_id, SUM(duration) AS tDuration
     FROM users
 WHERE date(start_datetime at TIME ZONE 'UTC') = '2020-05-01'
     GROUP BY project_id, user_id, office_id;

, и я создал индекс для такой таблицы

CREATE INDEX i1_users on users (date(start_datetime at TIME ZONE 'UTC'), project_id, user_id, office_id) include (duration);

, но он не выполняет сканирование индекса, так как все необходимые данные присутствуют в самом индексе

результат объяснения выглядит следующим образом

GroupAggregate  (cost=7.80..7.82 rows=1 width=36) (actual time=5.672..11.735 rows=298 loops=1)
  Group Key:project_id, user_id, office_id
  ->  Sort  (cost=7.80..7.80 rows=1 width=32) (actual time=5.632..7.527 rows=298 loops=1)
        Sort Key: project_id, user_id, office_id
        Sort Method: quicksort  Memory: 48kB
        ->  Index Scan using i2_users on users  (cost=0.56..7.79 rows=1 width=32) (actual time=0.034..2.616 rows=298 loops=1)
              Index Cond: (date(timezone('UTC'::text, start_datetime)) = '2020-05-01'::date)
Planning Time: 2.070 ms
Execution Time: 13.991 ms

Я тоже пробовал vacuum analyze users, но не повезло. И когда в таблице есть данные, он выполняет сканирование и сортировку последовательности, но поскольку в индексе есть отсортированные данные, почему бы просто не использовать это?

Ответы [ 2 ]

0 голосов
/ 12 июля 2020

Интеллект IOS -capable-обнаружения части планировщика здесь немного не впечатляет. Он составляет список всех столбцов, которые, по его мнению, ему необходимы, и проверяет их доступность, а также включает start_datetime в этот список. Эта часть кода не понимает, что наличие date(start_datetime at TIME ZONE 'UTC') устраняет необходимость в самом start_datetime.

Вы можете «исправить» это, добавив сам start_datetime в индекс, но из источника за счет увеличение индекса:

CREATE INDEX on users (date_trunc('day',start_datetime), project_id, user_id, office_id)
    include (duration,start_datetime);
0 голосов
/ 12 июля 2020

вы сравниваете дату «date (start_datetime at TIME ZONE 'UT C')» со строкой «2020-05-01», что предотвратит использование индекса. может помочь:

SELECT user_id, project_id, office_id, SUM(duration) AS tDuration
 FROM users
WHERE date(start_datetime at TIME ZONE 'UTC') = TO_DATE('2020-05-01','YYYY-MM-DD')
 GROUP BY project_id, user_id, office_id;

(часовой пояс может быть добавлен в to_date)

Но действительно ли вам нужно преобразование часового пояса? если столбец хранит только дату, используйте его напрямую (избегая индекса на основе функций, что позволяет улучшить статистику / оптимизацию):

CREATE INDEX i1_users on users (start_datetime, project_id, user_id, office_id) include (duration);
SELECT user_id, project_id, office_id, SUM(duration) AS tDuration
 FROM users WHERE start_datetime = to_date('2020-05-01','YYYY-MM-DD')
 GROUP BY project_id, user_id, office_id;

Если start_datetime содержит истинную метку времени:

CREATE INDEX i1_users on users (date_trunc('day',start_datetime), project_id, user_id, office_id) include (duration);

SELECT user_id, project_id, office_id, SUM(duration) AS tDuration
 FROM users WHERE date_trunc('day',start_datetime) = to_date('2020-05-01','YYYY-MM-DD')
 GROUP BY project_id, user_id, office_id;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...