Стратегия индексирования для различных комбинаций предложений WHERE, в т.ч.текстовые шаблоны - PullRequest
0 голосов
/ 29 марта 2019

Продолжение другого вопроса здесь:

Как получить запрос date_part для индекса попадания?

При выполнении следующего запроса он достигает составного индекса, созданного мнойполя datelocal, views, впечатлений, пола, возрастной группы:

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'
GROUP  BY 1
ORDER  BY 1;

Однако я хотел бы также иметь возможность отфильтровать этот запрос на основе дополнительных предложений в WHERE, например:

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'
AND network LIKE '%'
GROUP  BY 1
ORDER  BY 1;

Этот второй запрос НАМНОГО медленнее первого, хотя он должен работать с гораздо меньшим количеством записей, в дополнение к тому, что он не попадает в мой индекс.

Схема таблицы:

CREATE TABLE reportimpression (
    datelocal timestamp without time zone,
    devicename text,
    network text,
    sitecode text,
    advertisername text,
    mediafilename text,
    gender text,
    agegroup text,
    views integer,
    impressions integer,
    dwelltime numeric
);

-- Indices -------------------------------------------------------

CREATE INDEX reportimpression_datelocal_index ON reportimpression(datelocal timestamp_ops);
CREATE INDEX reportimpression_viewership_index ON reportimpression(datelocal timestamp_ops,views int4_ops,impressions int4_ops,gender text_ops,agegroup text_ops);
CREATE INDEX reportimpression_test_index ON reportimpression(datelocal timestamp_ops,(date_part('hour'::text, datelocal)) float8_ops);

Анализ выходных данных:

Finalize GroupAggregate  (cost=1005368.37..1005385.70 rows=3151 width=24) (actual time=70615.636..70615.649 rows=24 loops=1)
  Group Key: (date_part('hour'::text, datelocal))
  ->  Sort  (cost=1005368.37..1005369.94 rows=3151 width=24) (actual time=70615.631..70615.634 rows=48 loops=1)
        Sort Key: (date_part('hour'::text, datelocal))
        Sort Method: quicksort  Memory: 28kB
        ->  Gather  (cost=1005005.62..1005331.75 rows=3151 width=24) (actual time=70615.456..70641.208 rows=48 loops=1)
              Workers Planned: 1
              Workers Launched: 1
              ->  Partial HashAggregate  (cost=1004005.62..1004016.65 rows=3151 width=24) (actual time=70613.132..70613.152 rows=24 loops=2)
                    Group Key: date_part('hour'::text, datelocal)
                    ->  Parallel Seq Scan on reportimpression  (cost=0.00..996952.63 rows=2821195 width=17) (actual time=0.803..69876.914 rows=2429159 loops=2)
                          Filter: ((datelocal >= '2019-02-01 00:00:00'::timestamp without time zone) AND (datelocal < '2019-03-01 00:00:00'::timestamp without time zone) AND (network ~~ '%'::text))
                          Rows Removed by Filter: 6701736
Planning time: 0.195 ms
Execution time: 70641.349 ms

Нужно ли создавать дополнительные индексы, настраивать мой SELECT или что-то еще полностью?

1 Ответ

1 голос
/ 29 марта 2019

В добавленном предикате используется оператор LIKE:

AND network LIKE '%'

Фактический план запроса зависит от того, что вы передаете вместо «%». Но, как правило, простые индексы btree для этого бесполезны. Вам понадобится индекс триграммы или вы будете использовать инфраструктуру текстового поиска или подобное, в зависимости от того, какие шаблоны вы можете искать.

См:

Вы можете даже объединить несколько стратегий индексации. Пример:


Если это должно быть:

AND network = '<input_string>'

тогда, конечно, используйте оператор =, а не LIKE. Причины в порядке возрастания важности:

  1. короче
  2. менее запутанно
  3. упрощает работу планировщика Postgres (немного дешевле)
  4. правильный

    Если вы случайно передадите строку со специальными символами, вы можете получить неправильные результаты. См:

...