Функция массива Postgresql не использует индекс

Я создал столбец массива postgresql с индексом GIN и пытаюсь выполнить содержащий запрос для этого столбца. Со стандартным postgresql я могу заставить его работать правильно следующим образом:

SELECT d.name 
FROM deck d 
WHERE d.card_names_array @> string_to_array('"Anger#2","Pingle Who Annoys#2"', ',') 
LIMIT 20;

Объясните анализ:

Limit  (cost=1720.01..1724.02 rows=1 width=31) (actual time=7.787..7.787 rows=0 loops=1)
  ->  Bitmap Heap Scan on deck deck0_  (cost=1720.01..1724.02 rows=1 width=31) (actual time=7.787..7.787 rows=0 loops=1)
        Recheck Cond: (card_names_array @> '{"\"Anger#2\"","\"Pingle Who Annoys#2\""}'::text[])
        ->  Bitmap Index Scan on deck_card_names_array_idx  (cost=0.00..1720.01 rows=1 width=0) (actual time=7.785..7.785 rows=0 loops=1)
              Index Cond: (card_names_array @> '{"\"Anger#2\"","\"Pingle Who Annoys#2\""}'::text[])
Planning time: 0.216 ms
Execution time: 7.810 ms

К сожалению (в данном случае) я использую QueryDSL, с которым Я читал, что собственные функции массива, такие как @>, невозможно использовать. Однако в этот ответ говорится, что вместо этого вы можете использовать arraycontains, чтобы сделать то же самое. У меня это работает, и он возвращает правильные результаты, но не использует мой индекс.

SELECT d.name 
FROM deck d 
WHERE arraycontains(d.card_names_array, string_to_array('"Anger#2","Pingle Who Annoys#2"', ','))=true
LIMIT 20;

Объясните анализ:

Limit  (cost=0.00..18.83 rows=20 width=31) (actual time=1036.151..1036.151 rows=0 loops=1)
  ->  Seq Scan on deck deck0_  (cost=0.00..159065.60 rows=168976 width=31) (actual time=1036.150..1036.150 rows=0 loops=1)
        Filter: arraycontains(card_names_array, '{"\"Anger#2\"","\"Pingle Who Annoys#2\""}'::text[])
        Rows Removed by Filter: 584014
Planning time: 0.204 ms
Execution time: 1036.166 ms

Это мой код QueryDSL для создания логического выражения:

predicate.and(Expressions.booleanTemplate(
        "arraycontains({0}, string_to_array({1}, ','))=true",
        deckQ.cardNamesArray,
        filters.cards.joinToString(",") { "${it.cardName}#${it.quantity}" }
))

Есть ли способ заставить его использовать мой индекс? Или, может быть, другой способ сделать это с QueryDSL, чтобы использовать родную функцию @>?


person CorayThan    schedule 10.02.2019    source источник
comment
На самом деле это не ответ, но для моего варианта использования я понял, что могу просто проиндексировать одну строку со всеми значениями в ней и выполнить аналогичный запрос с %Anger#2%. Это достаточно производительно для моего варианта использования и означает, что мне не нужно выпрыгивать из песочницы querydsl.   -  person CorayThan    schedule 12.02.2019