Как оптимизировать запрос, если я уже использую индекс GIN - PullRequest
0 голосов
/ 28 мая 2020

Я использую (PostgreSQL) 11.8 и стараюсь предоставить возможность полнотекстового поиска по некоторым столбцам. Для этого я создал индекс GIN с несколькими полями и объединением. И после того, как моя база данных выросла до 344747 строк в табличных продуктах, я столкнулся с медленным выполнением своего запроса. Когда я выполняю пример запроса, я столкнулся примерно с 4,6 с. При анализе информации вижу, что мой индекс используется, но все же медленно. Сканирование растрового индекса на npdbcs_swedish_custom_index присутствует. Если я поправлю сделанный вывод, то на группировку потратил много времени. Кто-нибудь знает какой-либо подход или предложение, как оптимизировать этот запрос, потому что я не могу представить, как он будет работать, когда моя база данных вырастет до 10 миллионов продуктов. И больше всего надеюсь, что данные из ANALYZE - Planning Time: 0.790 ms это возможно?

->  GroupAggregate  (cost=27625.67..47476.93 rows=10284 width=928) (actual time=32.328..4490.279 rows=6634 loops=1)

мой индекс

create index npdbcs_swedish_custom_index on products
                    using GIN(to_tsvector('pg_catalog.swedish', name||price||description||brand||category||shop))

и мой запрос

 EXPLAIN ANALYZE
        SELECT                         
            products_alias.id,
            products_alias.sku,
            products_alias.name AS "name",
            products_alias.description,
            products_alias.category,
            products_alias.price,
            products_alias.shipping,
            products_alias.currency,
            products_alias.instock,
            products_alias.product_url AS "productUrl",
            products_alias.image_url AS "imageUrl",
            products_alias.tracking_url AS "trackingUrl",
            products_alias.brand,
            products_alias.shop,
            products_alias.original_price AS "originalPrice",
            products_alias.ean,
            products_alias.manufacturer_article_number AS "manufacturerArticleNumber",
            products_alias.extras,
            products_alias.created_at AS "createdAt",
            products_alias.brand_relation_id AS "brandRelationId",
            products_alias.shop_relation_id AS "shopRelationId",
            array_agg(DISTINCT cpt.category_id) AS categoryIds,
            COUNT(DISTINCT uip.id) as "numberOfEntries",
            ts_rank_cd(to_tsvector('pg_catalog.swedish', products_alias.name||products_alias.price||products_alias.description||products_alias.brand||products_alias.category||products_alias.shop), to_tsquery('pg_catalog.swedish', 'AeroMoov&Air&Layer™&Group&2&Sittdyna&Mörkgrå&One&Size:*|329.00|AeroMoov|Liggdelar|Duovagnar|Barnvagnar|Solskydd')) AS rank

        FROM products products_alias 
        LEFT JOIN user_ip_product uip on uip.products_id = products_alias.id 
                LEFT JOIN product_category cpt on cpt.product_id = products_alias.id
                WHERE to_tsvector('pg_catalog.swedish', products_alias.name||products_alias.price||products_alias.description||products_alias.brand||products_alias.category||products_alias.shop) @@ to_tsquery('pg_catalog.swedish', 'AeroMoov&Air&Layer™&Group&2&Sittdyna&Mörkgrå&One&Size:*|329.00|AeroMoov|Liggdelar|Duovagnar|Barnvagnar|Solskydd')             
        AND products_alias.id != 810429                                         
        GROUP BY products_alias.id ORDER BY rank DESC                                          
        LIMIT 4
        OFFSET 0;



Limit  (cost=47631.19..47631.20 rows=4 width=928) (actual time=4401.654..4401.656 rows=4 loops=1)
  ->  Sort  (cost=47631.19..47656.90 rows=10284 width=928) (actual time=4401.652..4401.653 rows=4 loops=1)
        Sort Key: (ts_rank_cd(to_tsvector('swedish'::regconfig, ((((((products_alias.name)::text || (products_alias.price)::text) || products_alias.description) || (products_alias.brand)::text) || (products_alias.category)::text) || (products_alias.shop)::text)), '''aeromoov'' & ''air'' & ''layer'' & ''group'' & ''2'' & ''sittdyn'' & ''mörkgrå'' & ''one'' & ''siz'':* | ''329.00'' | ''aeromoov'' | ''liggdel'' | ''duovagn'' | ''barnvagn'' | ''solskyd'''::tsquery)) DESC
        Sort Method: top-N heapsort  Memory: 31kB
        ->  GroupAggregate  (cost=27625.67..47476.93 rows=10284 width=928) (actual time=31.780..4382.917 rows=6634 loops=1)
              Group Key: products_alias.id
              ->  Gather Merge  (cost=27625.67..44420.18 rows=20203 width=892) (actual time=31.096..88.389 rows=13451 loops=1)
                    Workers Planned: 2
                    Workers Launched: 2
                    ->  Nested Loop Left Join  (cost=26625.65..41088.23 rows=8418 width=892) (actual time=24.549..52.293 rows=4484 loops=3)
                          ->  Merge Left Join  (cost=26625.22..26646.92 rows=4285 width=888) (actual time=24.513..29.039 rows=2212 loops=3)
                                Merge Cond: (products_alias.id = uip.products_id)
                                ->  Sort  (cost=26622.18..26632.89 rows=4285 width=884) (actual time=24.430..26.065 rows=2211 loops=3)
                                      Sort Key: products_alias.id
                                      Sort Method: external merge  Disk: 2808kB
                                      Worker 0:  Sort Method: quicksort  Memory: 3261kB
                                      Worker 1:  Sort Method: quicksort  Memory: 2112kB
                                      ->  Parallel Bitmap Heap Scan on products products_alias  (cost=283.70..26363.68 rows=4285 width=884) (actual time=8.825..17.986 rows=2211 loops=3)
                                            Recheck Cond: (to_tsvector('swedish'::regconfig, ((((((name)::text || (price)::text) || description) || (brand)::text) || (category)::text) || (shop)::text)) @@ '''aeromoov'' & ''air'' & ''layer'' & ''group'' & ''2'' & ''sittdyn'' & ''mörkgrå'' & ''one'' & ''siz'':* | ''329.00'' | ''aeromoov'' | ''liggdel'' | ''duovagn'' | ''barnvagn'' | ''solskyd'''::tsquery)
                                            Filter: (id <> 810429)
                                            Rows Removed by Filter: 0
                                            Heap Blocks: exact=2563
                                            ->  Bitmap Index Scan on npdbcs_swedish_custom_index  (cost=0.00..281.13 rows=10284 width=0) (actual time=10.858..10.859 rows=6635 loops=1)
                                                  Index Cond: (to_tsvector('swedish'::regconfig, ((((((name)::text || (price)::text) || description) || (brand)::text) || (category)::text) || (shop)::text)) @@ '''aeromoov'' & ''air'' & ''layer'' & ''group'' & ''2'' & ''sittdyn'' & ''mörkgrå'' & ''one'' & ''siz'':* | ''329.00'' | ''aeromoov'' | ''liggdel'' | ''duovagn'' | ''barnvagn'' | ''solskyd'''::tsquery)
                                ->  Sort  (cost=3.05..3.18 rows=53 width=8) (actual time=0.070..0.086 rows=59 loops=3)
                                      Sort Key: uip.products_id
                                      Sort Method: quicksort  Memory: 27kB
                                      Worker 0:  Sort Method: quicksort  Memory: 27kB
                                      Worker 1:  Sort Method: quicksort  Memory: 27kB
                                      ->  Seq Scan on user_ip_product uip  (cost=0.00..1.53 rows=53 width=8) (actual time=0.030..0.040 rows=59 loops=3)
                          ->  Index Scan using idx_cdfc73564584665a on product_category cpt  (cost=0.42..3.34 rows=3 width=8) (actual time=0.007..0.009 rows=2 loops=6636)
                                Index Cond: (product_id = products_alias.id)
Planning Time: 0.660 ms
Execution Time: 4402.940 ms

было бы здорово, если бы он потратил 0,660 мс. Как оптимизировать этот запрос?

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Попробуйте увеличить work_mem в надежде, что вы сможете получить более эффективный ha sh агрегат.

Я признаю, что меня удивляет то, что время тратится на агрегат группы ...

0 голосов
/ 28 мая 2020

было бы здорово, если бы он потратил 0,660 мс.

Время планирования - это время, затраченное на планирование выполнения. Дело не в том, сколько времени, по мнению планировщика, займет / должно занять выполнение плана. Нет причин думать, что ваша надежда здесь достижима, эти два числа представляют собой совершенно разные вещи. Это все равно что смотреть, сколько времени вы тратите на завязывание обуви, а не на марафон. Конечно, было бы неплохо, если бы вы могли пробежать марафон за то же время, которое требуется для ie вашей обуви, но нет причин думать, что это достижимо.

Я предполагаю, времени идет либо на вычисление ts_rank_cd, либо на сбор (возможно, TOASTed) входных данных, необходимых для его вычисления. Что произойдет, если вы удалите ts_rank_cd и выберите что-то еще для ЗАКАЗА? EXPLAIN VERBOSE в упрощенной версии вашего запроса подсказывает мне, что фактическая оценка ts_rank_cd происходит в правильном узле плана (т.е. медленном), чтобы это объяснение было правдоподобным.

Одна вещь, которая может сделать это быстрее, если вы сохраните вычисленный tsvector в таблицу как реальный столбец, а не вычисляете его динамически. Необходимое дополнительное хранилище - это, конечно, компромисс. таблица растет, ваше условие WHERE будет по-прежнему возвращать примерно такое же количество строк, или оно вернет примерно такую ​​же пропорцию таблицы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...