Мой запрос очень медленный, и мне нужно улучшить скорость (приведено ниже описание базы данных)
Мне нужно создать один запрос, который может:
- Сначала выберите все place_ids из place_table в радиусе
- Затем, используйте place_ids , чтобы найти все item_ids в items_table
- Затем отфильтруйте выбранные item_ids по:
- , определяя, содержит ли item_id определенный ключв items_indexed_table (Например: SELECT * FROM items_indexed_table WHERE key = 'foo_bar')
- определение, имеет ли этот элемент определенный цвет в таблице item_colors_table
Я создал несколько запросов, но они выполняются медленно (> 1 мин).Я считаю, что все таблицы правильно проиндексированы и используются, когда я запускаю EXPLAIN ANALYZE.Запросы JOIN и WITH AS () не помогают при попытке применить все описанные выше шаги.
Однако, когда я выполняю шаги 1 и 2 в одном запросе, он возвращает результаты менее чем за 500 мс, а когда я запускаю шаг3 только для определенного ключа и цвета, он также возвращает результаты менее чем за 500 мс.Проблема в том, что когда я пытаюсь присоединиться к ним, получение возврата занимает очень много времени.Я запустил EXPLAIN ANALYZE и обнаружил, что шаги 1 и 2 были выполнены последними.
Ниже приведены два запроса, упомянутых выше:
with nearest_items AS (
with nearest_places AS (
SELECT place_id
FROM places_table
WHERE (ST_DWithin(places_table.geometry, ST_MakePoint(some_lon, some_lat)::geography, 1500))
)
SELECT items_table.item_id
FROM items_table
WHERE items_table.place_id IN (SELECT place_id FROM nearest_places)
) SELECT * FROM nearest_items;
Время планирования: 0,457 мс
Время выполнения: 36,420 мс
Но когда я объединяю его, чтобы использовать его с item_indexed_table , скорость очень низкая.
with nearest_items AS (
with nearest_places AS (
SELECT place_id
FROM places_table
WHERE (ST_DWithin(places_table.geometry, ST_MakePoint(some_lon, some_lat)::geography, 1500))
)
SELECT items_table.item_id
FROM items_table
WHERE items_table.place_id IN (SELECT place_id FROM nearest_places)
)
SELECT
items_table.item_id
FROM
items_table
WHERE
items_tables.item_id in (
SELECT *
FROM nearest_items
)
and items_table.item_id in (
SELECT item_id
FROM item_indexed_table
WHERE key = 'medicine'
)
;
Вот ОБЪЯСНИТЕ АНАЛИЗ
Merge Join (cost=2003517.08..3623886.10 rows=1111500 width=37) (actual time=1834.616..29030.328 rows=61 loops=1)
Merge Cond: (nearest_items.item_id = items_table.item_id)
CTE nearest_items
-> Nested Loop (cost=15731.91..1414499.28 rows=17150069 width=37) (actual time=24.501..30.230 rows=5562 loops=1)
CTE nearest_restaurants
-> Gather (cost=1956.86..15549.89 rows=1389 width=37) (actual time=0.729..24.410 rows=19 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Parallel Bitmap Heap Scan on places_table (cost=956.86..14410.99 rows=579 width=37) (actual time=0.154..0.197 rows=6 loops=3)
Recheck Cond: ((geometry)::geography && '0101000020E61000008AE42B8194975DC02D776682E1F04040'::geography)
Filter: (('0101000020E61000008AE42B8194975DC02D776682E1F04040'::geography && _st_expand((geometry)::geography, '1500'::double precision)) AND _st_dwithin((geometry)::geography, '0101000020E61000008AE42B8194975DC02D776682E1F04040'::geography, '1500'::double precision, true))
Rows Removed by Filter: 3
Heap Blocks: exact=29
-> Bitmap Index Scan on places_geometry_to_geography_index (cost=0.00..956.51 rows=20831 width=0) (actual time=0.249..0.249 rows=29 loops=1)
Index Cond: ((geometry)::geography && '0101000020E61000008AE42B8194975DC02D776682E1F04040'::geography)
-> HashAggregate (cost=31.25..33.25 rows=200 width=32) (actual time=24.446..24.458 rows=19 loops=1)
Group Key: nearest_places.place_id
-> CTE Scan on nearest_places (cost=0.00..27.78 rows=1389 width=32) (actual time=0.731..24.428 rows=19 loops=1)
-> Bitmap Heap Scan on items_table items_table_1 (cost=150.76..6975.28 rows=1930 width=74) (actual time=0.035..0.165 rows=293 loops=19)
Recheck Cond: (place_id = nearest_places.place_id)
Heap Blocks: exact=470
-> Bitmap Index Scan on items_table_place_id_index (cost=0.00..150.28 rows=1930 width=0) (actual time=0.030..0.030 rows=293 loops=19)
Index Cond: (place_id = nearest_places.place_id)
-> Sort (cost=589017.24..591795.99 rows=1111500 width=69) (actual time=117.743..117.810 rows=61 loops=1)
Sort Key: items_table_index.item_id
Sort Method: quicksort Memory: 33kB
-> Nested Loop (cost=385877.25..386217.98 rows=1111500 width=69) (actual time=39.721..117.632 rows=61 loops=1)
-> HashAggregate (cost=385876.55..385878.55 rows=200 width=32) (actual time=36.690..39.319 rows=5562 loops=1)
Group Key: nearest_items.item_id
-> CTE Scan on nearest_items (cost=0.00..343001.38 rows=17150069 width=32) (actual time=24.504..33.625 rows=5562 loops=1)
-> Index Only Scan using items_table_index_pkey on itema_table_index (cost=0.70..32.82 rows=32 width=37) (actual time=0.013..0.013 rows=0 loops=5562)
Index Cond: ((item_id = nearest_items.item_id) AND (key = 'medicine'::text))
Heap Fetches: 34
-> Index Only Scan using items_table_pkey on items_table (cost=0.56..1517926.72 rows=34308144 width=37) (actual time=0.020..14910.737 rows=33838956 loops=1)
Heap Fetches: 2567
Вот изображение, показывающее дизайн базы данных
https://ibb.co/GV8MpqV
Ожидаемый запрос
SELECT item_id
FROM item_tables
WHERE (ST_DWithin(places_table.geometry, ST_MakePoint(some_lon, some_lat)::geography, 1500))
AND (
(item_indexed_table.key = 'medicine')
OR (item_indexed_table.key = 'potato' AND item_indexed_table.key = 'chips')
)
AND (items_color_table.color_id = 'f32nr-kfr32')
- Простой английский:Выберите все идентификаторы предметов, которые находятся в радиусе вашего местоположения и содержат слово «лекарство» или слова «картофель» и «чип», а цветовой идентификатор равен «f32nr-kfr32»
ОжидаетсяРезультаты
- список item_ids (должен быть в радиусе и должен иметь возможность фильтровать по цвету и ключу из других таблиц)
- Мои таблицы очень большие, поэтому я бы хотелполучить время выполнения как можно меньше
Вотразмеры таблиц
placse_table: ~ 100000 строк
item_table: ~ 4000000 строк
item_index_table:> 100000000 строк
item_colors_table:> 1000000 строк
Я хотел бы любую помощь или советы, которые кто-нибудь может дать, Спасибо!