У меня есть таблица с 50K строк. На самом деле это таблица PostGIS.
Запрос состоит из 4 частей (1 обязательная) (3 необязательных)
- прямоугольник пересечения (прямоугольник географии) с длиной 4 лат (я использую st_intersects) [обязательно]
- Диапазон дат (мин., Макс.) В поле даты
- Тип файла (набор до 8 текстовых значений), в настоящее время использующий IN (.....), но я могу сделать это временной таблицей, если это необходимо. Я вижу, что многие люди не любят IN.
- Страна (текстовое значение).
Я ожидаю около 100 - 4000 возвращенных строк
Если я создаю составной индекс в таблице, какой столбец я должен использовать в первую очередь. Мелкозернистое - это, вероятно, место (данные распространены по всему миру). В настоящее время у меня есть это как индекс GIST.
Другие индексы будут BTREE.
Моя интуиция говорит, что использовать мелкозернистый, и, конечно, последний. Например, существует всего около 12 типов файлов, так что это будет очень большие сегменты для индекса.
Что говорят гуру PostgreSQL и PostGIS (кто знает внутренности системы)?
ОБНОВИТЬ:
Позвольте мне обострить этот вопрос.
- Я не хочу, чтобы кто-то делал ту работу, которую я должен делать. Я слишком уважаю твое время. Так что я объясню позже.
- Все, что я искал, это несколько указателей, советов и рекомендаций.
- Я прочитал эту прекрасную небольшую заметку: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintenance-indexes об индексах
- Обычно я создаю 4 отдельных индекса (геобокс, название страны, тип_файла и дата), но при этом хочу посмотреть, что будет делать составной запрос.
Скажите, если какое-либо из этих предположений неверно. (Я довольно новичок в идее составных индексов)
- Порядок важен. Выберите в качестве первого индекса тот, который будет сокращать строки больше всего (в моем случае лучше всего подойдет местоположение (география), которое представляет собой простой многоугольник или многоугольник).
- Иногда запросы будут пропускать индексы. Но если я создаю составной запрос с ключом (# 1, # 2, # 3, # 4), то даже если пользователь создает что-то, что запрашивает # 1, # 3, планировщик все равно будет использовать один составной запрос, так как они упорядочивают поддерживается.
- Обычно я бы создал три BTREE-запроса и один GIST (для типа географии). PostGIS не поддерживает создание соединения из нескольких типов индекса. Поэтому мне придется использовать GIST составной индекс. Но это не должно повредить вещи.
- Если я создам несколько дополнительных составных или единичных индексов значений, планировщик достаточно умен, чтобы выбрать наиболее разумный .....
- Название страны может иметь около 250 различных значений и, очевидно, тесно связано с местоположением (геобокс), но если следующий лучший индекс для сокращения размера строки - это file_type, я должен использовать его следующим. Я не ожидаю, что пользователи будут часто использовать страну или дату в своих наборах запросов.
- Мне НЕ нужно беспокоиться о том, что создание составного индекса из 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'))
источник
EXPLAIN ANALYZE
по запросу.Ответы:
В рамках своей работы я поддерживаю довольно большую базу данных PostgreSQL (около 120 ГБ на диске, несколько таблиц с несколькими миллионами строк) и собрал несколько трюков о том, как ускорить запросы. Сначала несколько комментариев о ваших предположениях:
Я бы посоветовал не делать четырехсторонний индекс. Попробуйте создать его, а затем проверьте размер, они могут стать действительно огромными. По моему опыту, четыре одноклавишных индекса были почти такими же быстрыми, как один четырехпозиционный. Уловка, которая хорошо работает для некоторых конкретных запросов, - это частичные индексы, то есть что-то вроде этого:
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 ();
источник
Я думаю, что наиболее вероятной вещью, которая поможет (если вообще что-нибудь), будет добавление product_type в качестве 2-го столбца к основному индексу. Но не зная, сколько строк соответствует каждому из условий AND (изолированно) для ваших типичных / проблемных запросов, мы можем только догадываться.
Когда я подхожу к этому, первое, что я делаю, это запускаю запрос в упрощенной форме, где предложение WHERE имеет только одно условие, каждое из которых выполняется по очереди, в EXPLAIN ANALYZE. Посмотрите как оценочные строки и фактические строки для каждого.
источник