Порядок столбцов в составном индексе в PostgreSQL (и порядок запросов)

10

У меня есть таблица с 50K строк. На самом деле это таблица PostGIS.

Запрос состоит из 4 частей (1 обязательная) (3 необязательных)

  1. прямоугольник пересечения (прямоугольник географии) с длиной 4 лат (я использую st_intersects) [обязательно]
  2. Диапазон дат (мин., Макс.) В поле даты
  3. Тип файла (набор до 8 текстовых значений), в настоящее время использующий IN (.....), но я могу сделать это временной таблицей, если это необходимо. Я вижу, что многие люди не любят IN.
  4. Страна (текстовое значение).

Я ожидаю около 100 - 4000 возвращенных строк

Если я создаю составной индекс в таблице, какой столбец я должен использовать в первую очередь. Мелкозернистое - это, вероятно, место (данные распространены по всему миру). В настоящее время у меня есть это как индекс GIST.

Другие индексы будут BTREE.

Моя интуиция говорит, что использовать мелкозернистый, и, конечно, последний. Например, существует всего около 12 типов файлов, так что это будет очень большие сегменты для индекса.

Что говорят гуру PostgreSQL и PostGIS (кто знает внутренности системы)?


ОБНОВИТЬ:

Позвольте мне обострить этот вопрос.

  1. Я не хочу, чтобы кто-то делал ту работу, которую я должен делать. Я слишком уважаю твое время. Так что я объясню позже.
  2. Все, что я искал, это несколько указателей, советов и рекомендаций.
  3. Я прочитал эту прекрасную небольшую заметку: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintenance-indexes об индексах
  4. Обычно я создаю 4 отдельных индекса (геобокс, название страны, тип_файла и дата), но при этом хочу посмотреть, что будет делать составной запрос.

Скажите, если какое-либо из этих предположений неверно. (Я довольно новичок в идее составных индексов)

  1. Порядок важен. Выберите в качестве первого индекса тот, который будет сокращать строки больше всего (в моем случае лучше всего подойдет местоположение (география), которое представляет собой простой многоугольник или многоугольник).
  2. Иногда запросы будут пропускать индексы. Но если я создаю составной запрос с ключом (# 1, # 2, # 3, # 4), то даже если пользователь создает что-то, что запрашивает # 1, # 3, планировщик все равно будет использовать один составной запрос, так как они упорядочивают поддерживается.
  3. Обычно я бы создал три BTREE-запроса и один GIST (для типа географии). PostGIS не поддерживает создание соединения из нескольких типов индекса. Поэтому мне придется использовать GIST составной индекс. Но это не должно повредить вещи.
  4. Если я создам несколько дополнительных составных или единичных индексов значений, планировщик достаточно умен, чтобы выбрать наиболее разумный .....
  5. Название страны может иметь около 250 различных значений и, очевидно, тесно связано с местоположением (геобокс), но если следующий лучший индекс для сокращения размера строки - это file_type, я должен использовать его следующим. Я не ожидаю, что пользователи будут часто использовать страну или дату в своих наборах запросов.
  6. Мне НЕ нужно беспокоиться о том, что создание составного индекса из 4 ключей значительно увеличит размер данных индекса. Т.е. если индекс с одним ключом будет составлять 90% прироста производительности, то не помешает добавить еще 3 элемента, чтобы сделать его составным. И наоборот, я действительно должен создать оба индекса. Единый географический индекс, а также составной индекс, и пусть планировщик выяснит, какой из них лучше, и он будет учитывать размер таблицы индексов.

Опять же, я не прошу никого разрабатывать свое решение, я не отношусь к работе других. Но мне нужны вещи, которые в документации PostGreSQL не говорят мне о реализации

[Причина, по которой у меня пока нет результата EXPLAIN, заключается в том, что я должен создать эту таблицу строк размером 25 КБ из таблицы строк размером 24 МБ. Это занимает больше времени, чем я думал. Я группирую вещи в 1000 групп элементов и позволяю пользователю выполнять запросы к таблице строк 25K. Но мой следующий вопрос будет заключаться в использовании результатов этого запроса для перехода к таблице строк MASTER 25M и извлечения информации, и именно здесь производительность составного индекса действительно ХИТ].


Пример запроса ниже:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

ОБЪЯСНИТЬ АНАЛИЗ результатов (я не вставлял никаких составных индексов, и по скорости, которую я вижу, я не знаю, нужно ли мне).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
Dr.YSG
источник
2
Укажите актуальный запрос, пожалуйста.
ypercubeᵀᴹ
Означает ли «3 необязательных», что запрос может иметь 8 различных вариантов (в зависимости от того, активированы опции 2,3,4 или нет)?
ypercubeᵀᴹ
В ГДЕ есть 4 И компонента. На st_intersects требуется, другие могут быть, или они не могут. Но я хочу разобраться со случаем, когда все они присутствуют.
2
Я проголосовал за перенос вопроса на dba.se, это сложный запрос с несколькими диапазонами условий.
ypercubeᵀᴹ
1
Показать EXPLAIN ANALYZEпо запросу.
Крейг Рингер

Ответы:

4

В рамках своей работы я поддерживаю довольно большую базу данных PostgreSQL (около 120 ГБ на диске, несколько таблиц с несколькими миллионами строк) и собрал несколько трюков о том, как ускорить запросы. Сначала несколько комментариев о ваших предположениях:

  1. Да, порядок важен, но только первый действительно отличается, остальные - индексы второго класса.
  2. Я не уверен, что он всегда будет использовать оба, я предполагаю, что планировщик запросов будет использовать # 1, а затем делать что-то умное с остальными.
  3. У меня нет опыта работы с GIST.
  4. Да, сначала добавьте все индексы, посмотрите, что используется чаще всего, а что дает наилучшую производительность.
  5. Я бы посоветовал вам попробовать оба и измерить то, что работает лучше всего. Попробуйте переписать sql с разными подзапросами, возможно, страной и временем в одном, а затем присоединитесь к intersect-query. Я не заметил каких-либо проблем с производительностью в IN-предложениях, поскольку IN-список не состоит из тысяч элементов. Я предполагаю, что несколько разных запросов, специально настроенных в зависимости от доступных критериев ввода, дадут наилучшие результаты.
  6. Я бы посоветовал не делать четырехсторонний индекс. Попробуйте создать его, а затем проверьте размер, они могут стать действительно огромными. По моему опыту, четыре одноклавишных индекса были почти такими же быстрыми, как один четырехпозиционный. Уловка, которая хорошо работает для некоторых конкретных запросов, - это частичные индексы, то есть что-то вроде этого:

    CREATE INDEX ON table_x (key1, key2, key3) WHERE some_x_column = 'XXXX';

Я создал псевдонимы в своем .psqlrc-файле с запросами, чтобы помочь найти, какие индексы добавить или удалить. Не стесняйтесь взглянуть на них на GitHub: .psql

Я часто использую: seq_scans и: bigtables, а затем \ d table_name, чтобы получить подробную информацию о таблице. Не забудьте сбросить статистику после внесения некоторых изменений, выберите pg_stat_reset ();

Клас Могрен
источник
1
Это отличные советы. Я воспользовался вашим советом, а затем использовал его, чтобы провести эксперимент на гораздо большей таблице, которую мы поддерживаем (43 миллиона строк). Результаты находятся по адресу: dba.stackexchange.com/questions/61084/…
Dr.YSG
1

Я думаю, что наиболее вероятной вещью, которая поможет (если вообще что-нибудь), будет добавление product_type в качестве 2-го столбца к основному индексу. Но не зная, сколько строк соответствует каждому из условий AND (изолированно) для ваших типичных / проблемных запросов, мы можем только догадываться.

Когда я подхожу к этому, первое, что я делаю, это запускаю запрос в упрощенной форме, где предложение WHERE имеет только одно условие, каждое из которых выполняется по очереди, в EXPLAIN ANALYZE. Посмотрите как оценочные строки и фактические строки для каждого.

jjanes
источник
см. мое обновление выше, но я думаю, что вы даете мне хорошее преимущество, подумайте о порядке упорядочения индексов, по которым вывод строки будет выполняться быстрее всего. Это правильно?
Dr.YSG